From 8fb9df97511532a28ac8225282318dd1f31be0e4 Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Wed, 3 Jun 2015 18:35:38 -0700 Subject: delete dead test code --- java/src/com/zerotier/one/AndroidFileProvider.java | 43 ----- java/src/com/zerotier/one/DataStore.java | 73 -------- .../com/zerotier/one/DataStoreFileProvider.java | 12 -- java/src/com/zerotier/one/JavaFileProvider.java | 46 ----- java/src/com/zerotier/one/OneService.java | 204 --------------------- 5 files changed, 378 deletions(-) delete mode 100644 java/src/com/zerotier/one/AndroidFileProvider.java delete mode 100644 java/src/com/zerotier/one/DataStore.java delete mode 100644 java/src/com/zerotier/one/DataStoreFileProvider.java delete mode 100644 java/src/com/zerotier/one/JavaFileProvider.java delete mode 100644 java/src/com/zerotier/one/OneService.java 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 . - * - * -- - * - * 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 - - } -} -- cgit v1.2.3 From b84dba3ecb2f750f5b5fda39544e20f741f961a4 Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Wed, 3 Jun 2015 21:29:07 -0700 Subject: more logging --- java/jni/com_zerotierone_sdk_Node.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/java/jni/com_zerotierone_sdk_Node.cpp b/java/jni/com_zerotierone_sdk_Node.cpp index f0405813..c84524fa 100644 --- a/java/jni/com_zerotierone_sdk_Node.cpp +++ b/java/jni/com_zerotierone_sdk_Node.cpp @@ -416,10 +416,15 @@ namespace { { // 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); @@ -736,12 +741,14 @@ 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, ZT1_RESULT_FATAL_ERROR_INTERNAL); } unsigned int nbtd_len = env->GetArrayLength(out_nextBackgroundTaskDeadline); if(nbtd_len < 1) { + LOGE("nbtd_len < 1"); return createResultObject(env, ZT1_RESULT_FATAL_ERROR_INTERNAL); } @@ -751,6 +758,7 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processWirePacket( jclass inetAddressClass = cache.findClass("java/net/InetAddress"); if(inetAddressClass == NULL) { + LOGE("Can't find InetAddress class"); // can't find java.net.InetAddress return createResultObject(env, ZT1_RESULT_FATAL_ERROR_INTERNAL); } @@ -849,6 +857,10 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processWirePacket( packetData, packetLength, &nextBackgroundTaskDeadline); + if(rc != ZT1_RESULT_OK) + { + LOGE("ZT1_Node_processWirePacket returned: %d", rc); + } jlong *outDeadline = env->GetLongArrayElements(out_nextBackgroundTaskDeadline, NULL); outDeadline[0] = (jlong)nextBackgroundTaskDeadline; -- cgit v1.2.3 From 7cc64c5cb69f2962d32ca41f6dc12499964d22a7 Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Wed, 3 Jun 2015 21:29:19 -0700 Subject: Might help to set the enabled field on a VirtualNetworkConfig object :) --- java/jni/ZT1_jniutils.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/java/jni/ZT1_jniutils.cpp b/java/jni/ZT1_jniutils.cpp index e6404e87..36f68f9e 100644 --- a/java/jni/ZT1_jniutils.cpp +++ b/java/jni/ZT1_jniutils.cpp @@ -822,6 +822,7 @@ jobject newNetworkConfig(JNIEnv *env, const ZT1_VirtualNetworkConfig &vnetConfig 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"); -- cgit v1.2.3 From ced040c5033bd61a963e65e8e8525459c4b8b59d Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Tue, 9 Jun 2015 19:38:05 -0700 Subject: Logging and adding .equals() methods to MulticastGroup and VirtualNetworkCofnig --- java/jni/ZT1_jniutils.cpp | 10 +++--- java/jni/com_zerotierone_sdk_Node.cpp | 12 ++++--- java/src/com/zerotier/sdk/MulticastGroup.java | 4 +++ .../src/com/zerotier/sdk/VirtualNetworkConfig.java | 38 ++++++++++++++++++++++ 4 files changed, 54 insertions(+), 10 deletions(-) diff --git a/java/jni/ZT1_jniutils.cpp b/java/jni/ZT1_jniutils.cpp index 36f68f9e..1e8a48bf 100644 --- a/java/jni/ZT1_jniutils.cpp +++ b/java/jni/ZT1_jniutils.cpp @@ -343,18 +343,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: @@ -818,7 +818,7 @@ jobject newNetworkConfig(JNIEnv *env, const ZT1_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); diff --git a/java/jni/com_zerotierone_sdk_Node.cpp b/java/jni/com_zerotierone_sdk_Node.cpp index c84524fa..2a90bb85 100644 --- a/java/jni/com_zerotierone_sdk_Node.cpp +++ b/java/jni/com_zerotierone_sdk_Node.cpp @@ -92,7 +92,7 @@ namespace { enum ZT1_VirtualNetworkConfigOperation operation, const ZT1_VirtualNetworkConfig *config) { - LOGD("VritualNetworkConfigFunctionCallback"); + LOGV("VritualNetworkConfigFunctionCallback"); JniRef *ref = (JniRef*)userData; JNIEnv *env = NULL; ref->jvm->GetEnv((void**)&env, JNI_VERSION_1_6); @@ -142,7 +142,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; @@ -188,7 +190,7 @@ namespace { void EventCallback(ZT1_Node *node,void *userData,enum ZT1_Event event, const void *data) { - LOGD("EventCallback"); + LOGV("EventCallback"); JniRef *ref = (JniRef*)userData; assert(ref->node == node); JNIEnv *env = NULL; @@ -436,7 +438,7 @@ namespace { const void *buffer, unsigned int bufferSize) { - LOGD("WirePacketSendFunction(%p, %p, %d)", address, buffer, bufferSize); + LOGV("WirePacketSendFunction(%p, %p, %d)", address, buffer, bufferSize); JniRef *ref = (JniRef*)userData; assert(ref->node == node); @@ -464,7 +466,7 @@ namespace { env->SetByteArrayRegion(bufferObj, 0, bufferSize, (jbyte*)buffer); int retval = env->CallIntMethod(ref->packetSender, packetSenderCallbackMethod, addressObj, bufferObj); - LOGD("JNI Packet Sender returned: %d", retval); + LOGV("JNI Packet Sender returned: %d", retval); return retval; } 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/VirtualNetworkConfig.java b/java/src/com/zerotier/sdk/VirtualNetworkConfig.java index 2be03acb..35453ddc 100644 --- a/java/src/com/zerotier/sdk/VirtualNetworkConfig.java +++ b/java/src/com/zerotier/sdk/VirtualNetworkConfig.java @@ -54,6 +54,44 @@ public final class VirtualNetworkConfig { } + public boolean equals(VirtualNetworkConfig cfg) { + boolean mcgEqual = true; + if(multicastSubscriptions.length == cfg.multicastSubscriptions.length) { + for(int i = 0; i < multicastSubscriptions.length; ++i) { + if(!multicastSubscriptions[i].equals(cfg.multicastSubscriptions[i])) + { + return false; + } + } + } else { + mcgEqual = false; + } + + 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 && + mcgEqual && aaEqual; + } + /** * 64-bit ZeroTier network ID */ -- cgit v1.2.3 From 3013d90f579ac970e41000d6732e798589c3ac90 Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Tue, 9 Jun 2015 22:38:31 -0700 Subject: ignore windows binary output --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 498119e3..95f6ed5b 100755 --- a/.gitignore +++ b/.gitignore @@ -71,3 +71,4 @@ java/doc/ java/build_win64/ java/build_win32/ /java/mac32_64/ +windows/ZeroTierOne/Debug/ -- cgit v1.2.3 From 4dc0ff8f13a2a5d852cda9302632d58b25d045ac Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Tue, 9 Jun 2015 23:12:44 -0700 Subject: Replace calls to GetArrayElements with GetPrimitiveArrayCritical. This puts code accessing the data in a critical section so that the GC cannot run while JNI has access to the array. This helps with stability somewhat, but I'm still getting some crashes in the GC --- java/jni/com_zerotierone_sdk_Node.cpp | 54 +++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/java/jni/com_zerotierone_sdk_Node.cpp b/java/jni/com_zerotierone_sdk_Node.cpp index 2a90bb85..62fbba89 100644 --- a/java/jni/com_zerotierone_sdk_Node.cpp +++ b/java/jni/com_zerotierone_sdk_Node.cpp @@ -174,9 +174,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()) { @@ -356,13 +356,13 @@ 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); @@ -700,7 +700,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; @@ -712,15 +715,15 @@ 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); - outDeadline[0] = (jlong)nextBackgroundTaskDeadline; - env->ReleaseLongArrayElements(out_nextBackgroundTaskDeadline, outDeadline, 0); + - env->ReleaseByteArrayElements(in_frameData, frameData, 0); + jlong *outDeadline = (jlong*)env->GetPrimitiveArrayCritical(out_nextBackgroundTaskDeadline, NULL); + outDeadline[0] = (jlong)nextBackgroundTaskDeadline; + env->ReleasePrimitiveArrayCritical(out_nextBackgroundTaskDeadline, outDeadline, 0); return createResultObject(env, rc); } @@ -816,8 +819,7 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processWirePacket( unsigned int addrSize = env->GetArrayLength(addressArray); // get the address bytes - jbyte *addr = env->GetByteArrayElements(addressArray, NULL); - + jbyte *addr = (jbyte*)env->GetPrimitiveArrayCritical(addressArray, NULL); sockaddr_storage remoteAddress = {}; @@ -842,13 +844,16 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processWirePacket( else { // unknown address type - env->ReleaseByteArrayElements(addressArray, addr, 0); + env->ReleasePrimitiveArrayCritical(addressArray, addr, 0); return createResultObject(env, ZT1_RESULT_FATAL_ERROR_INTERNAL); } - + env->ReleasePrimitiveArrayCritical(addressArray, addr, 0); unsigned int packetLength = env->GetArrayLength(in_packetData); - jbyte *packetData = env->GetByteArrayElements(in_packetData, NULL); + 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; @@ -856,7 +861,7 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processWirePacket( node, now, &remoteAddress, - packetData, + localData, packetLength, &nextBackgroundTaskDeadline); if(rc != ZT1_RESULT_OK) @@ -864,12 +869,11 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processWirePacket( LOGE("ZT1_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); } @@ -904,9 +908,9 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processBackgroundTasks( ZT1_ResultCode rc = ZT1_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); } -- cgit v1.2.3 From 6889fcfc28ad7df236e9883c17d73c9badb8edd5 Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Tue, 9 Jun 2015 23:24:47 -0700 Subject: Looks like it was the JNI cash causing the crash. Forcing it to look up classes and methods instead of caching them stopped the crashes in the GC. Will investigate more later. --- java/jni/ZT1_jnicache.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/java/jni/ZT1_jnicache.cpp b/java/jni/ZT1_jnicache.cpp index 8d6305cb..4deec61f 100644 --- a/java/jni/ZT1_jnicache.cpp +++ b/java/jni/ZT1_jnicache.cpp @@ -111,7 +111,7 @@ jclass JniCache::findClass(const std::string &name) jclass cls = (jclass)env->NewGlobalRef(localCls); - m_classes.insert(std::make_pair(name, cls)); + //m_classes.insert(std::make_pair(name, cls)); return cls; } @@ -143,7 +143,7 @@ jmethodID JniCache::findMethod(jclass cls, const std::string &methodName, const return NULL; } - m_methods.insert(std::make_pair(id, mid)); + //m_methods.insert(std::make_pair(id, mid)); return mid; } @@ -173,7 +173,7 @@ jmethodID JniCache::findStaticMethod(jclass cls, const std::string &methodName, return NULL; } - m_staticMethods.insert(std::make_pair(id, mid)); + //m_staticMethods.insert(std::make_pair(id, mid)); return mid; } @@ -203,7 +203,7 @@ jfieldID JniCache::findField(jclass cls, const std::string &fieldName, const std return NULL; } - m_fields.insert(std::make_pair(id, fid)); + //m_fields.insert(std::make_pair(id, fid)); return fid; } @@ -233,7 +233,7 @@ jfieldID JniCache::findStaticField(jclass cls, const std::string &fieldName, con return NULL; } - m_staticFields.insert(std::make_pair(id, fid)); + //m_staticFields.insert(std::make_pair(id, fid)); return fid; } -- cgit v1.2.3 From 7e84f5a7dbb50913a78311df4f748455be0e1097 Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Tue, 9 Jun 2015 23:24:54 -0700 Subject: killing whitespace --- java/jni/com_zerotierone_sdk_Node.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/java/jni/com_zerotierone_sdk_Node.cpp b/java/jni/com_zerotierone_sdk_Node.cpp index 62fbba89..9516db41 100644 --- a/java/jni/com_zerotierone_sdk_Node.cpp +++ b/java/jni/com_zerotierone_sdk_Node.cpp @@ -719,8 +719,6 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processVirtualNetworkFrame( frameLength, &nextBackgroundTaskDeadline); - - jlong *outDeadline = (jlong*)env->GetPrimitiveArrayCritical(out_nextBackgroundTaskDeadline, NULL); outDeadline[0] = (jlong)nextBackgroundTaskDeadline; env->ReleasePrimitiveArrayCritical(out_nextBackgroundTaskDeadline, outDeadline, 0); -- cgit v1.2.3 From 472206dfb23e8c2d285d5cdf19ba1444d07e4d52 Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Wed, 10 Jun 2015 20:16:13 -0700 Subject: Rename JniCache to JniLookup Removed caching capabilities as the cached methods, fields, and objects appears to be broken on Android --- java/CMakeLists.txt | 2 +- java/jni/Android.mk | 2 +- java/jni/ZT1_jnicache.cpp | 242 ---------------------------------- java/jni/ZT1_jnicache.h | 65 --------- java/jni/ZT1_jnilookup.cpp | 158 ++++++++++++++++++++++ java/jni/ZT1_jnilookup.h | 54 ++++++++ java/jni/ZT1_jniutils.cpp | 132 +++++++++---------- java/jni/com_zerotierone_sdk_Node.cpp | 68 +++++----- 8 files changed, 314 insertions(+), 409 deletions(-) delete mode 100644 java/jni/ZT1_jnicache.cpp delete mode 100644 java/jni/ZT1_jnicache.h create mode 100644 java/jni/ZT1_jnilookup.cpp create mode 100644 java/jni/ZT1_jnilookup.h diff --git a/java/CMakeLists.txt b/java/CMakeLists.txt index db3eec1c..382fd3cd 100644 --- a/java/CMakeLists.txt +++ b/java/CMakeLists.txt @@ -54,7 +54,7 @@ set(src_files ../osdep/OSUtils.cpp jni/com_zerotierone_sdk_Node.cpp jni/ZT1_jniutils.cpp - jni/ZT1_jnicache.cpp + jni/ZT1_jnilookup.cpp ) set(include_dirs diff --git a/java/jni/Android.mk b/java/jni/Android.mk index bbf14348..9986c2c3 100644 --- a/java/jni/Android.mk +++ b/java/jni/Android.mk @@ -39,6 +39,6 @@ LOCAL_SRC_FILES := \ LOCAL_SRC_FILES += \ com_zerotierone_sdk_Node.cpp \ ZT1_jniutils.cpp \ - ZT1_jnicache.cpp + ZT1_jnilookup.cpp include $(BUILD_SHARED_LIBRARY) \ No newline at end of file diff --git a/java/jni/ZT1_jnicache.cpp b/java/jni/ZT1_jnicache.cpp deleted file mode 100644 index 4deec61f..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 . - * - * -- - * - * 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 "ZT1_jnicache.h" -#include "ZT1_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/ZT1_jnicache.h b/java/jni/ZT1_jnicache.h deleted file mode 100644 index 43f43a08..00000000 --- a/java/jni/ZT1_jnicache.h +++ /dev/null @@ -1,65 +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 . - * - * -- - * - * 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 ZT1_JNICACHE_H_ -#define ZT1_JNICACHE_H_ - -#include -#include -#include - - - -class JniCache { -public: - JniCache(); - JniCache(JavaVM *jvm); - ~JniCache(); - - void setJavaVM(JavaVM *jvm); - void clearCache(); - - jclass findClass(const std::string &name); - jmethodID findMethod(jclass cls, const std::string &methodName, const std::string &methodSig); - jmethodID findStaticMethod(jclass cls, const std::string &methodName, const std::string &methodSig); - 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 MethodMap; - typedef std::map FieldMap; - typedef std::map 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_jnilookup.cpp b/java/jni/ZT1_jnilookup.cpp new file mode 100644 index 00000000..d8f5cc7f --- /dev/null +++ b/java/jni/ZT1_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 . + * + * -- + * + * 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 "ZT1_jnilookup.h" +#include "ZT1_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_jnilookup.h b/java/jni/ZT1_jnilookup.h new file mode 100644 index 00000000..cf496f88 --- /dev/null +++ b/java/jni/ZT1_jnilookup.h @@ -0,0 +1,54 @@ +/* + * 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 . + * + * -- + * + * 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 ZT1_JNILOOKUP_H_ +#define ZT1_JNILOOKUP_H_ + +#include +#include +#include + + + +class JniLookup { +public: + JniLookup(); + JniLookup(JavaVM *jvm); + ~JniLookup(); + + void setJavaVM(JavaVM *jvm); + + jclass findClass(const std::string &name); + jmethodID findMethod(jclass cls, const std::string &methodName, const std::string &methodSig); + jmethodID findStaticMethod(jclass cls, const std::string &methodName, const std::string &methodSig); + 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: + JavaVM *m_jvm; +}; + +#endif \ No newline at end of file diff --git a/java/jni/ZT1_jniutils.cpp b/java/jni/ZT1_jniutils.cpp index 1e8a48bf..ac04eb58 100644 --- a/java/jni/ZT1_jniutils.cpp +++ b/java/jni/ZT1_jniutils.cpp @@ -1,9 +1,9 @@ #include "ZT1_jniutils.h" -#include "ZT1_jnicache.h" +#include "ZT1_jnilookup.h" #include #include -extern JniCache cache; +extern JniLookup lookup; #ifdef __cplusplus extern "C" { @@ -15,7 +15,7 @@ jobject createResultObject(JNIEnv *env, ZT1_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, ZT1_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, ZT1_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, ZT1_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, ZT1_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; @@ -147,7 +147,7 @@ jobject createEvent(JNIEnv *env, ZT1_Event event) 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 +159,7 @@ jobject createPeerRole(JNIEnv *env, ZT1_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; @@ -179,7 +179,7 @@ jobject createPeerRole(JNIEnv *env, ZT1_PeerRole role) 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 +191,7 @@ jobject createVirtualNetworkType(JNIEnv *env, ZT1_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 +208,7 @@ jobject createVirtualNetworkType(JNIEnv *env, ZT1_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 +218,7 @@ jobject createVirtualNetworkConfigOperation(JNIEnv *env, ZT1_VirtualNetworkConfi 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 +241,7 @@ jobject createVirtualNetworkConfigOperation(JNIEnv *env, ZT1_VirtualNetworkConfi 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 +252,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 +315,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 +330,7 @@ jobject newInetSocketAddress(JNIEnv *env, const sockaddr_storage &addr) return NULL; } - inetSocketAddress_constructor = cache.findMethod( + inetSocketAddress_constructor = lookup.findMethod( inetSocketAddressClass, "", "(Ljava/net/InetAddress;I)V"); if(env->ExceptionCheck() || inetSocketAddress_constructor == NULL) { @@ -380,13 +380,13 @@ jobject newMulticastGroup(JNIEnv *env, const ZT1_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, "", "()V"); if(env->ExceptionCheck() || multicastGroup_constructor == NULL) { @@ -399,13 +399,13 @@ jobject newMulticastGroup(JNIEnv *env, const ZT1_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; @@ -431,56 +431,56 @@ jobject newPeerPhysicalPath(JNIEnv *env, const ZT1_PeerPhysicalPath &ppp) 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"); + fixedField = lookup.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, "", "()V"); + ppp_constructor = lookup.findMethod(pppClass, "", "()V"); if(env->ExceptionCheck() || ppp_constructor == NULL) { LOGE("Error finding PeerPhysicalPath constructor"); @@ -532,77 +532,77 @@ jobject newPeer(JNIEnv *env, const ZT1_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, "", "()V"); + peer_constructor = lookup.findMethod(peerClass, "", "()V"); if(env->ExceptionCheck() || peer_constructor == NULL) { LOGE("Error finding Peer constructor"); @@ -625,7 +625,7 @@ jobject newPeer(JNIEnv *env, const ZT1_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 +675,14 @@ jobject newNetworkConfig(JNIEnv *env, const ZT1_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, "", "()V"); if(env->ExceptionCheck() || vnetConfig_constructor == NULL) { @@ -697,98 +697,98 @@ jobject newNetworkConfig(JNIEnv *env, const ZT1_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"); @@ -825,7 +825,7 @@ jobject newNetworkConfig(JNIEnv *env, const ZT1_VirtualNetworkConfig &vnetConfig 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"); @@ -850,7 +850,7 @@ jobject newNetworkConfig(JNIEnv *env, const ZT1_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"); @@ -887,13 +887,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, "", "()V"); if(env->ExceptionCheck() || versionConstructor == NULL) { @@ -912,25 +912,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/com_zerotierone_sdk_Node.cpp b/java/jni/com_zerotierone_sdk_Node.cpp index 9516db41..aa42c548 100644 --- a/java/jni/com_zerotierone_sdk_Node.cpp +++ b/java/jni/com_zerotierone_sdk_Node.cpp @@ -27,7 +27,7 @@ #include "com_zerotierone_sdk_Node.h" #include "ZT1_jniutils.h" -#include "ZT1_jnicache.h" +#include "ZT1_jnilookup.h" #include @@ -36,8 +36,8 @@ #include #include -// global static JNI Cache Object -JniCache cache; +// global static JNI Lookup Object +JniLookup lookup; #ifdef __cplusplus extern "C" { @@ -104,7 +104,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) @@ -158,7 +158,7 @@ namespace { return; } - jmethodID frameListenerCallbackMethod = cache.findMethod( + jmethodID frameListenerCallbackMethod = lookup.findMethod( frameListenerClass, "onVirtualNetworkFrame", "(JJJJJ[B)V"); if(env->ExceptionCheck() || frameListenerCallbackMethod == NULL) @@ -204,7 +204,7 @@ namespace { return; } - jmethodID onEventMethod = cache.findMethod(eventListenerClass, + jmethodID onEventMethod = lookup.findMethod(eventListenerClass, "onEvent", "(Lcom/zerotier/sdk/Event;)V"); if(onEventMethod == NULL) { @@ -213,7 +213,7 @@ namespace { } - jmethodID onOutOfDateMethod = cache.findMethod(eventListenerClass, + jmethodID onOutOfDateMethod = lookup.findMethod(eventListenerClass, "onOutOfDate", "(Lcom/zerotier/sdk/Version;)V"); if(onOutOfDateMethod == NULL) { @@ -222,7 +222,7 @@ namespace { } - jmethodID onNetworkErrorMethod = cache.findMethod(eventListenerClass, + jmethodID onNetworkErrorMethod = lookup.findMethod(eventListenerClass, "onNetworkError", "(Lcom/zerotier/sdk/Event;Ljava/net/InetSocketAddress;)V"); if(onNetworkErrorMethod == NULL) { @@ -231,7 +231,7 @@ namespace { } - jmethodID onTraceMethod = cache.findMethod(eventListenerClass, + jmethodID onTraceMethod = lookup.findMethod(eventListenerClass, "onTrace", "(Ljava/lang/String;)V"); if(onTraceMethod == NULL) { @@ -316,7 +316,7 @@ namespace { return -2; } - jmethodID dataStoreGetCallbackMethod = cache.findMethod( + jmethodID dataStoreGetCallbackMethod = lookup.findMethod( dataStoreGetClass, "onDataStoreGet", "(Ljava/lang/String;[BJ[J)J"); @@ -388,7 +388,7 @@ namespace { return -1; } - jmethodID dataStorePutCallbackMethod = cache.findMethod( + jmethodID dataStorePutCallbackMethod = lookup.findMethod( dataStorePutClass, "onDataStorePut", "(Ljava/lang/String;[BZ)I"); @@ -398,7 +398,7 @@ namespace { return -2; } - jmethodID deleteMethod = cache.findMethod(dataStorePutClass, + jmethodID deleteMethod = lookup.findMethod(dataStorePutClass, "onDelete", "(Ljava/lang/String;)I"); if(deleteMethod == NULL) { @@ -453,7 +453,7 @@ namespace { return -1; } - jmethodID packetSenderCallbackMethod = cache.findMethod(packetSenderClass, + jmethodID packetSenderCallbackMethod = lookup.findMethod(packetSenderClass, "onSendPacketRequested", "(Ljava/net/InetSocketAddress;[B)I"); if(packetSenderCallbackMethod == NULL) { @@ -487,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(); + } @@ -514,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) @@ -529,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) @@ -544,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) { @@ -558,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) { @@ -572,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) { @@ -586,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) { @@ -758,7 +758,7 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processWirePacket( 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"); @@ -766,7 +766,7 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processWirePacket( return createResultObject(env, ZT1_RESULT_FATAL_ERROR_INTERNAL); } - jmethodID getAddressMethod = cache.findMethod( + jmethodID getAddressMethod = lookup.findMethod( inetAddressClass, "getAddress", "()[B"); if(getAddressMethod == NULL) { @@ -774,13 +774,13 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processWirePacket( return createResultObject(env, ZT1_RESULT_FATAL_ERROR_INTERNAL); } - jclass InetSocketAddressClass = cache.findClass("java/net/InetSocketAddress"); + jclass InetSocketAddressClass = lookup.findClass("java/net/InetSocketAddress"); if(InetSocketAddressClass == NULL) { return createResultObject(env, ZT1_RESULT_FATAL_ERROR_INTERNAL); } - jmethodID inetSockGetAddressMethod = cache.findMethod( + jmethodID inetSockGetAddressMethod = lookup.findMethod( InetSocketAddressClass, "getAddress", "()Ljava/net/InetAddress;"); jobject addrObject = env->CallObjectMethod(in_remoteAddress, inetSockGetAddressMethod); @@ -790,7 +790,7 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processWirePacket( return createResultObject(env, ZT1_RESULT_FATAL_ERROR_INTERNAL); } - jmethodID inetSock_getPort = cache.findMethod( + jmethodID inetSock_getPort = lookup.findMethod( InetSocketAddressClass, "getPort", "()I"); if(env->ExceptionCheck() || inetSock_getPort == NULL) @@ -1059,13 +1059,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, "", "()V"); if(nodeStatusConstructor == NULL) { @@ -1086,25 +1086,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; @@ -1207,7 +1207,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"); @@ -1265,7 +1265,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"); -- cgit v1.2.3 From abbcb0a12cbab782c1d9879391efb65e9cd92acf Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Sat, 13 Jun 2015 14:38:04 -0700 Subject: Modified ant build script so that it can be integrated with Android Studio's build system --- java/build.xml | 39 ++++++++++++--------------------------- 1 file changed, 12 insertions(+), 27 deletions(-) diff --git a/java/build.xml b/java/build.xml index e24a0e13..93d754a6 100644 --- a/java/build.xml +++ b/java/build.xml @@ -1,4 +1,4 @@ - + @@ -9,7 +9,7 @@ - + @@ -24,6 +24,10 @@ + + + + - + @@ -91,7 +95,7 @@ overwrite="true"/> - + @@ -101,23 +105,4 @@ - - \ No newline at end of file -- cgit v1.2.3 From adf89901c4d2de0d2338889a7fa1e5df1ab6b9be Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Fri, 19 Jun 2015 19:00:06 -0700 Subject: dont consider multicast groups in VirtualNetworkConfig.equals() --- java/src/com/zerotier/sdk/VirtualNetworkConfig.java | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/java/src/com/zerotier/sdk/VirtualNetworkConfig.java b/java/src/com/zerotier/sdk/VirtualNetworkConfig.java index 35453ddc..980f48f7 100644 --- a/java/src/com/zerotier/sdk/VirtualNetworkConfig.java +++ b/java/src/com/zerotier/sdk/VirtualNetworkConfig.java @@ -55,18 +55,6 @@ public final class VirtualNetworkConfig { } public boolean equals(VirtualNetworkConfig cfg) { - boolean mcgEqual = true; - if(multicastSubscriptions.length == cfg.multicastSubscriptions.length) { - for(int i = 0; i < multicastSubscriptions.length; ++i) { - if(!multicastSubscriptions[i].equals(cfg.multicastSubscriptions[i])) - { - return false; - } - } - } else { - mcgEqual = false; - } - boolean aaEqual = true; if(assignedAddresses.length == cfg.assignedAddresses.length) { for(int i = 0; i < assignedAddresses.length; ++i) { @@ -89,7 +77,7 @@ public final class VirtualNetworkConfig { broadcastEnabled == cfg.broadcastEnabled && portError == cfg.portError && enabled == cfg.enabled && - mcgEqual && aaEqual; + aaEqual; } /** -- cgit v1.2.3 From 759d71037ef429c0277d8bebe16cc4ac1f426c45 Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Tue, 23 Jun 2015 23:03:02 -0700 Subject: added Comparable interface to VirtualNetworkConfig so we can sort arrays containing it. --- java/src/com/zerotier/sdk/VirtualNetworkConfig.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/java/src/com/zerotier/sdk/VirtualNetworkConfig.java b/java/src/com/zerotier/sdk/VirtualNetworkConfig.java index 980f48f7..278fafd2 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 { public static final int MAX_MULTICAST_SUBSCRIPTIONS = 4096; public static final int ZT1_MAX_ZT_ASSIGNED_ADDRESSES = 16; @@ -80,6 +82,14 @@ public final class VirtualNetworkConfig { 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 */ -- cgit v1.2.3 From bfb152f53f528934583ee76437453a005610a7ea Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Wed, 24 Jun 2015 20:31:22 -0700 Subject: configure the NDK to build all supported ABIs and package them up in the jar --- java/build.xml | 15 ++++++++++++--- java/jni/Application.mk | 5 +++-- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/java/build.xml b/java/build.xml index 93d754a6..4bc1cdc0 100644 --- a/java/build.xml +++ b/java/build.xml @@ -43,18 +43,27 @@ - + + + + diff --git a/java/jni/Application.mk b/java/jni/Application.mk index 3118ec2e..8b6c8020 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 - +APP_CPPFLAGS += -Wall -fPIE -fstack-protector -fexceptions +APP_PLATFORM := android-14 +APP_ABI := all -- cgit v1.2.3 From c9919cc5bae5c06980a701b8a4fa4d31805d4428 Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Fri, 26 Jun 2015 18:26:57 -0700 Subject: reflect changes to ZT1_PeerRole in JNI --- java/jni/ZT1_jniutils.cpp | 8 ++++---- java/src/com/zerotier/sdk/PeerRole.java | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/java/jni/ZT1_jniutils.cpp b/java/jni/ZT1_jniutils.cpp index 6b877417..90f3bb84 100644 --- a/java/jni/ZT1_jniutils.cpp +++ b/java/jni/ZT1_jniutils.cpp @@ -171,11 +171,11 @@ jobject createPeerRole(JNIEnv *env, ZT1_PeerRole role) case ZT1_PEER_ROLE_LEAF: fieldName = "PEER_ROLE_LEAF"; break; - case ZT1_PEER_ROLE_HUB: - fieldName = "PEER_ROLE_HUB"; + case ZT1_PEER_ROLE_RELAY: + fieldName = "PEER_ROLE_RELAY"; break; - case ZT1_PEER_ROLE_ROOTSERVER: - fieldName = "PEER_ROLE_ROOTSERVER"; + case ZT1_PEER_ROLE_ROOT: + fieldName = "PEER_ROLE_ROOT"; break; } 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 -- cgit v1.2.3 From aee8e95d4961195b3251bcc8581677a8f0c0cdd8 Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Tue, 30 Jun 2015 19:21:46 -0700 Subject: logging --- java/jni/com_zerotierone_sdk_Node.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/java/jni/com_zerotierone_sdk_Node.cpp b/java/jni/com_zerotierone_sdk_Node.cpp index aa42c548..ca4c4838 100644 --- a/java/jni/com_zerotierone_sdk_Node.cpp +++ b/java/jni/com_zerotierone_sdk_Node.cpp @@ -365,7 +365,7 @@ namespace { env->ReleasePrimitiveArrayCritical(objectSizeObj, objSize, 0); } - LOGI("Out Object Size: %lu", *out_objectSize); + LOGV("Out Object Size: %lu", *out_objectSize); return retval; } @@ -410,12 +410,14 @@ 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) -- cgit v1.2.3 From f803dd5ff46cc03e07364961eb23feb64b7697bd Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Wed, 1 Jul 2015 18:13:39 -0700 Subject: ... --- java/build.xml | 1 + java/jni/Android.mk | 1 + java/jni/com_zerotierone_sdk_Node.cpp | 8 +++++++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/java/build.xml b/java/build.xml index 4bc1cdc0..4604ad66 100644 --- a/java/build.xml +++ b/java/build.xml @@ -42,6 +42,7 @@ + node == node); + if(ref->node != node) + { + LOGE("Nodes not equal. ref->node %p, node %p", ref->node, node); + return; + } JNIEnv *env = NULL; ref->jvm->GetEnv((void**)&env, JNI_VERSION_1_6); @@ -613,6 +617,8 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_node_1init( &VirtualNetworkConfigFunctionCallback, &EventCallback); + LOGI("Node Created."); + if(rc != ZT1_RESULT_OK) { LOGE("Error creating Node: %d", rc); -- cgit v1.2.3 From 0b7cd2f40a9502a797eff49db12f6f892e319f45 Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Wed, 1 Jul 2015 20:26:14 -0700 Subject: change some build settings. add a lock --- java/CMakeLists.txt | 1 + java/jni/Android.mk | 1 + java/jni/Application.mk | 6 +++--- java/jni/com_zerotierone_sdk_Node.cpp | 23 ++++++++++++++++++++--- 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/java/CMakeLists.txt b/java/CMakeLists.txt index 382fd3cd..484517f8 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/jni/Android.mk b/java/jni/Android.mk index 15ba3875..56e6fb80 100644 --- a/java/jni/Android.mk +++ b/java/jni/Android.mk @@ -4,6 +4,7 @@ include $(CLEAR_VARS) LOCAL_MODULE := ZeroTierOneJNI LOCAL_C_INCLUDES := $(ZT1)/include +LOCAL_C_INCLUDES += $(ZT1)/node LOCAL_LDLIBS := -llog # LOCAL_CFLAGS := -g diff --git a/java/jni/Application.mk b/java/jni/Application.mk index 8b6c8020..0f369730 100644 --- a/java/jni/Application.mk +++ b/java/jni/Application.mk @@ -1,5 +1,5 @@ -APP_ABI := armeabi armeabi-v7a arm64-v8a x86 -APP_STL := gnustl_static -APP_CPPFLAGS += -Wall -fPIE -fstack-protector -fexceptions +NDK_TOOLCHAIN_VERSION := clang +APP_STL := c++_static +APP_CPPFLAGS := -O2 -fPIE -fvectorize -Wall -fstack-protector -fexceptions -fno-strict-aliasing APP_PLATFORM := android-14 APP_ABI := all diff --git a/java/jni/com_zerotierone_sdk_Node.cpp b/java/jni/com_zerotierone_sdk_Node.cpp index e8f7272b..e98342e7 100644 --- a/java/jni/com_zerotierone_sdk_Node.cpp +++ b/java/jni/com_zerotierone_sdk_Node.cpp @@ -30,6 +30,7 @@ #include "ZT1_jnilookup.h" #include +#include "Mutex.hpp" #include #include @@ -192,9 +193,9 @@ namespace { { LOGV("EventCallback"); JniRef *ref = (JniRef*)userData; - if(ref->node != node) + if(ref->node != node && event != ZT1_EVENT_UP) { - LOGE("Nodes not equal. ref->node %p, node %p", ref->node, node); + LOGE("Nodes not equal. ref->node %p, node %p. Event: %d", ref->node, node, event); return; } JNIEnv *env = NULL; @@ -478,9 +479,11 @@ namespace { typedef std::map NodeMap; static NodeMap nodeMap; + ZeroTier::Mutex nodeMapMutex; ZT1_Node* findNode(uint64_t nodeId) { + ZeroTier::Mutex::Lock lock(nodeMapMutex); NodeMap::iterator found = nodeMap.find(nodeId); if(found != nodeMap.end()) { @@ -633,8 +636,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; } @@ -650,7 +655,12 @@ JNIEXPORT void JNICALL Java_com_zerotier_sdk_Node_node_1delete( LOGV("Destroying ZT1_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; @@ -819,6 +829,7 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processWirePacket( jbyteArray addressArray = (jbyteArray)env->CallObjectMethod(addrObject, getAddressMethod); if(addressArray == NULL) { + LOGE("Unable to call getAddress()"); // unable to call getAddress() return createResultObject(env, ZT1_RESULT_FATAL_ERROR_INTERNAL); } @@ -849,6 +860,7 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processWirePacket( } else { + LOGE("Unknown IP version"); // unknown address type env->ReleasePrimitiveArrayCritical(addressArray, addr, 0); return createResultObject(env, ZT1_RESULT_FATAL_ERROR_INTERNAL); @@ -856,6 +868,11 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processWirePacket( env->ReleasePrimitiveArrayCritical(addressArray, addr, 0); unsigned int packetLength = env->GetArrayLength(in_packetData); + if(packetLength == 0) + { + LOGE("Empty packet?!?"); + return createResultObject(env, ZT1_RESULT_FATAL_ERROR_INTERNAL); + } void *packetData = env->GetPrimitiveArrayCritical(in_packetData, NULL); void *localData = malloc(packetLength); memcpy(localData, packetData, packetLength); -- cgit v1.2.3 From ab34884e3e47eb611d42312eb05079119f62e8b8 Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Fri, 3 Jul 2015 18:14:50 -0700 Subject: Set -O0 anything above that currently goes kaboom on ARM platforms --- java/jni/Application.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/jni/Application.mk b/java/jni/Application.mk index 0f369730..5f68ef6e 100644 --- a/java/jni/Application.mk +++ b/java/jni/Application.mk @@ -1,5 +1,5 @@ NDK_TOOLCHAIN_VERSION := clang APP_STL := c++_static -APP_CPPFLAGS := -O2 -fPIE -fvectorize -Wall -fstack-protector -fexceptions -fno-strict-aliasing +APP_CPPFLAGS := -O0 -fPIC -fPIE -fvectorize -Wall -fstack-protector -fexceptions -fno-strict-aliasing APP_PLATFORM := android-14 APP_ABI := all -- cgit v1.2.3 From a408e5f6858a0e2f13c27e56f203b35f64ab07e7 Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Wed, 8 Jul 2015 17:59:53 -0700 Subject: set ZT_NO_TYPE_PUNNING and -O3 for Android builds --- java/jni/Application.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/jni/Application.mk b/java/jni/Application.mk index 5f68ef6e..2a789787 100644 --- a/java/jni/Application.mk +++ b/java/jni/Application.mk @@ -1,5 +1,5 @@ NDK_TOOLCHAIN_VERSION := clang APP_STL := c++_static -APP_CPPFLAGS := -O0 -fPIC -fPIE -fvectorize -Wall -fstack-protector -fexceptions -fno-strict-aliasing +APP_CPPFLAGS := -O3 -fPIC -fPIE -fvectorize -Wall -fstack-protector -fexceptions -fno-strict-aliasing -DZT_NO_TYPE_PUNNING=1 APP_PLATFORM := android-14 APP_ABI := all -- cgit v1.2.3 From e45475c5b5bcee4fb88e797a50eb38b6ad3d6923 Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Thu, 9 Jul 2015 20:26:23 -0700 Subject: fixed a misspelling --- java/src/com/zerotier/sdk/EventListener.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/src/com/zerotier/sdk/EventListener.java b/java/src/com/zerotier/sdk/EventListener.java index 078023d9..bb191c1d 100644 --- a/java/src/com/zerotier/sdk/EventListener.java +++ b/java/src/com/zerotier/sdk/EventListener.java @@ -42,7 +42,7 @@ public interface EventListener { public void onEvent(Event event); /** - * Callback for network error events: {@link Event.EVENT_AUTHENTICATION_FAILUER}, {link Event.EVENT_INVALID_PACKET} + * Callback for network error events: {@link Event.EVENT_AUTHENTICATION_FAILURE}, {link Event.EVENT_INVALID_PACKET} * * @param event {@link Event} enum * @param source {@link InetSocketAddress} containing the origin address of the packet -- cgit v1.2.3 From d5b48c90edd801f41a40783312deca9f233605ae Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Thu, 27 Aug 2015 19:51:27 -0700 Subject: added a 512x512 app icon (for Play store) --- artwork/ZeroTierIcon512x512.png | Bin 0 -> 51309 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 artwork/ZeroTierIcon512x512.png diff --git a/artwork/ZeroTierIcon512x512.png b/artwork/ZeroTierIcon512x512.png new file mode 100644 index 00000000..d225c2e3 Binary files /dev/null and b/artwork/ZeroTierIcon512x512.png differ -- cgit v1.2.3 From 73bedfcc016e69b682dc916d26490c3810482ce0 Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Sat, 29 Aug 2015 17:54:30 -0700 Subject: ifdef default assignments --- include/ZeroTierOne.h | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 8583aa3a..b8d14c5f 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -760,7 +760,11 @@ enum ZT1_ResultCode ZT1_Node_new( ZT1_VirtualNetworkFrameFunction virtualNetworkFrameFunction, ZT1_VirtualNetworkConfigFunction virtualNetworkConfigFunction, ZT1_EventCallback eventCallback, - const char *overrideRootTopology = (const char *)0); + const char *overrideRootTopology +#ifdef __cplusplus + = (const char *)0 +#endif + ); /** * Delete a node and free all resources it consumes @@ -881,7 +885,11 @@ enum ZT1_ResultCode ZT1_Node_leave(ZT1_Node *node,uint64_t nwid); * @param multicastAdi Multicast ADI (least significant 32 bits only, default: 0) * @return OK (0) or error code if a fatal error condition has occurred */ -enum ZT1_ResultCode ZT1_Node_multicastSubscribe(ZT1_Node *node,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi = 0); +enum ZT1_ResultCode ZT1_Node_multicastSubscribe(ZT1_Node *node,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi +#ifdef __cplusplus + = 0 +#endif + ); /** * Unsubscribe from an Ethernet multicast group (or all groups) @@ -897,7 +905,11 @@ enum ZT1_ResultCode ZT1_Node_multicastSubscribe(ZT1_Node *node,uint64_t nwid,uin * @param multicastAdi Multicast ADI (least significant 32 bits only, default: 0) * @return OK (0) or error code if a fatal error condition has occurred */ -enum ZT1_ResultCode ZT1_Node_multicastUnsubscribe(ZT1_Node *node,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi = 0); +enum ZT1_ResultCode ZT1_Node_multicastUnsubscribe(ZT1_Node *node,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi +#ifdef __cplusplus + = 0 +#endif + ); /** * Get this node's 40-bit ZeroTier address -- cgit v1.2.3 From 0b9e5928d35c43748d8cd413e05e5718f7b1fc52 Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Sat, 26 Sep 2015 13:53:38 -0700 Subject: update PacketSender interface --- java/src/com/zerotier/sdk/PacketSender.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/java/src/com/zerotier/sdk/PacketSender.java b/java/src/com/zerotier/sdk/PacketSender.java index 5302f5ce..ab31729b 100644 --- a/java/src/com/zerotier/sdk/PacketSender.java +++ b/java/src/com/zerotier/sdk/PacketSender.java @@ -37,11 +37,13 @@ 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.

* - * @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, + InetSocketAddress localAddr, + InetSocketAddress remoteAddr, byte[] packetData); } -- cgit v1.2.3 From 7c3be2b5c152e8631237c1050e0c90ad37dfcb1d Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Sat, 26 Sep 2015 14:10:16 -0700 Subject: fix function signature in lookup for onSendPacketRequested function --- java/jni/com_zerotierone_sdk_Node.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/jni/com_zerotierone_sdk_Node.cpp b/java/jni/com_zerotierone_sdk_Node.cpp index e513cdf5..e1b69d1e 100644 --- a/java/jni/com_zerotierone_sdk_Node.cpp +++ b/java/jni/com_zerotierone_sdk_Node.cpp @@ -462,7 +462,7 @@ namespace { } jmethodID packetSenderCallbackMethod = lookup.findMethod(packetSenderClass, - "onSendPacketRequested", "(Ljava/net/InetSocketAddress;[B)I"); + "onSendPacketRequested", "(Ljava/net/InetSocketAddress;Ljava/net/InetSocketAddress;[B)I"); if(packetSenderCallbackMethod == NULL) { LOGE("Couldn't find onSendPacketRequested method"); -- cgit v1.2.3 From 75a191a8564030f4d5e99aca76b980e2d69abd20 Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Sat, 26 Sep 2015 14:10:45 -0700 Subject: don't create an InetSocketAddress on local address if it's equal to ZT_SOCKADDR_NULL --- java/jni/com_zerotierone_sdk_Node.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/java/jni/com_zerotierone_sdk_Node.cpp b/java/jni/com_zerotierone_sdk_Node.cpp index e1b69d1e..e6042649 100644 --- a/java/jni/com_zerotierone_sdk_Node.cpp +++ b/java/jni/com_zerotierone_sdk_Node.cpp @@ -469,7 +469,12 @@ namespace { return -2; } - jobject localAddressObj = newInetSocketAddress(env, *localAddress); + 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); -- cgit v1.2.3 From 64aaea3978533a6643850f6ed05a9afe7f4dc7be Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 6 Oct 2015 18:04:53 -0700 Subject: Cleanup, and add an even faster Poly1305 on systems that support it. --- node/Poly1305.cpp | 311 +++++++++++++++++++++++++++++++++++++++++++++++------- node/Utils.cpp | 4 +- 2 files changed, 273 insertions(+), 42 deletions(-) diff --git a/node/Poly1305.cpp b/node/Poly1305.cpp index 77b32a80..0968170e 100644 --- a/node/Poly1305.cpp +++ b/node/Poly1305.cpp @@ -132,9 +132,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__) + +////////////////////////////////////////////////////////////////////////////// +// 128-bit implementation for MSC and GCC + +#if defined(_MSC_VER) + #include + + 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 @@ -256,43 +483,6 @@ poly1305_blocks(poly1305_state_internal_t *st, const unsigned char *m, size_t by st->h[4] = h4; } -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; @@ -380,6 +570,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/Utils.cpp b/node/Utils.cpp index 658c397d..3c6dee32 100644 --- a/node/Utils.cpp +++ b/node/Utils.cpp @@ -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; } @@ -200,7 +200,7 @@ void Utils::getSecureRandom(void *buf,unsigned int bytes) for(unsigned int i=0;i= 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"); + fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() unable to read from /dev/urandom\n"); exit(1); return; } -- cgit v1.2.3 From 598a1d8dd7f621bb75a7f0537c5a63ee93e85a4c Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 6 Oct 2015 18:10:40 -0700 Subject: Try reopening /dev/urandom if there is a problem. --- node/Utils.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/node/Utils.cpp b/node/Utils.cpp index 3c6dee32..6c5d8c7d 100644 --- a/node/Utils.cpp +++ b/node/Utils.cpp @@ -181,7 +181,7 @@ void Utils::getSecureRandom(void *buf,unsigned int bytes) #ifdef __UNIX_LIKE__ - static char randomBuf[65536]; + static char randomBuf[131072]; static unsigned int randomPtr = sizeof(randomBuf); static int devURandomFd = -1; static Mutex globalLock; @@ -199,10 +199,16 @@ void Utils::getSecureRandom(void *buf,unsigned int bytes) for(unsigned int i=0;i= sizeof(randomBuf)) { - if ((int)::read(devURandomFd,randomBuf,sizeof(randomBuf)) != (int)sizeof(randomBuf)) { - fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() unable to read from /dev/urandom\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; } -- cgit v1.2.3 From 1b2cac0cc59790620262f447588274440c7fbefa Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 7 Oct 2015 09:38:33 -0700 Subject: Trim some cruft that is not used and probably never would be. --- include/ZeroTierOne.h | 27 +-------------------------- node/IncomingPacket.cpp | 18 ++---------------- node/Node.cpp | 16 +--------------- node/Node.hpp | 6 ------ 4 files changed, 4 insertions(+), 63 deletions(-) diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 341bb767..611e3699 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -255,31 +255,6 @@ 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 * @@ -287,7 +262,7 @@ enum ZT_Event * * Meta-data: C string, TRACE message */ - ZT_EVENT_TRACE = 8 + ZT_EVENT_TRACE = 5 }; /** diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 305232ee..26d4bda8 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -227,7 +227,6 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) 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); @@ -236,11 +235,9 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) outp.armor(key,true); RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); } 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()); } } 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()); } @@ -249,7 +246,6 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) // Identity is the same as the one we already have -- check packet integrity if (!dearmor(peer->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; } @@ -261,7 +257,6 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) // 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; } @@ -269,7 +264,6 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) // Check packet integrity and authentication SharedPtr 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; } @@ -284,11 +278,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) 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; - } + bool trusted = RR->topology->isRoot(id); if (destAddr) RR->sa->iam(id.address(),_remoteAddress,destAddr,trusted,RR->node->now()); @@ -369,11 +359,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p 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; - } + bool trusted = RR->topology->isRoot(peer->identity()); if (destAddr) RR->sa->iam(peer->address(),_remoteAddress,destAddr,trusted,RR->node->now()); } break; diff --git a/node/Node.cpp b/node/Node.cpp index d5cc50b9..d5ca147c 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -82,9 +82,6 @@ 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 @@ -540,16 +537,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,...) { @@ -659,8 +646,7 @@ enum ZT_ResultCode ZT_Node_processWirePacket( } catch (std::bad_alloc &exc) { return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; } catch ( ... ) { - reinterpret_cast(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 } } diff --git a/node/Node.hpp b/node/Node.hpp index 20c54471..0ae176c0 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -226,11 +226,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 @@ -288,7 +283,6 @@ private: uint64_t _now; uint64_t _lastPingCheck; uint64_t _lastHousekeepingRun; - unsigned int _newestVersionSeen[3]; // major, minor, revision bool _online; }; -- cgit v1.2.3 From 6c7ce79c8960cd2360657f9247788ff5640ae974 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 7 Oct 2015 09:51:35 -0700 Subject: Be consistent in how enums are defined in the main .h file. --- include/ZeroTierOne.h | 130 +++++++++++++++++++++++++------------------------- 1 file changed, 65 insertions(+), 65 deletions(-) diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 611e3699..990f682d 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -389,6 +389,68 @@ enum ZT_VirtualNetworkConfigOperation ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY = 4 }; +/** + * Local interface trust levels + */ +enum ZT_LocalInterfaceAddressTrust { + ZT_LOCAL_INTERFACE_ADDRESS_TRUST_NORMAL = 0, + ZT_LOCAL_INTERFACE_ADDRESS_TRUST_PRIVACY = 10, + ZT_LOCAL_INTERFACE_ADDRESS_TRUST_ULTIMATE = 20 +}; + +/** + * 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 */ @@ -536,15 +598,6 @@ typedef struct int preferred; } 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 */ @@ -610,59 +663,6 @@ typedef struct unsigned long peerCount; } 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 */ @@ -775,7 +775,7 @@ typedef struct { /** * Remote device vendor ID */ - ZT_Vendor vendor; + enum ZT_Vendor vendor; /** * Remote device protocol compliance version @@ -800,12 +800,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 -- cgit v1.2.3 From ab0228f626573381db93173cd5849cb934481ca5 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 7 Oct 2015 10:30:47 -0700 Subject: More cleanup and simple refactoring, consolidate InetAddres serialize/deserialize into the class. --- node/IncomingPacket.cpp | 102 +++++++++++++++++------------------------------- node/InetAddress.hpp | 5 ++- node/Packet.hpp | 15 ++----- node/Peer.cpp | 19 +-------- 4 files changed, 43 insertions(+), 98 deletions(-) diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 26d4bda8..6186affd 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -46,6 +46,7 @@ namespace ZeroTier { bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) { + 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 @@ -54,23 +55,24 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) return _doHELLO(RR); } - SharedPtr peer = RR->topology->getPeer(source()); + SharedPtr 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_ERROR: return _doERROR(RR,peer); @@ -90,13 +92,13 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) case Packet::VERB_CIRCUIT_TEST_REPORT: return _doCIRCUIT_TEST_REPORT(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,7 +110,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr const uint64_t inRePacketId = at(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) { @@ -118,7 +120,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr 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) { SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); - if ((network)&&(network->controller() == source())) + if ((network)&&(network->controller() == peer->address())) network->setNotFound(); } break; @@ -126,7 +128,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr case Packet::ERROR_UNSUPPORTED_OPERATION: if (inReVerb == Packet::VERB_NETWORK_CONFIG_REQUEST) { SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); - if ((network)&&(network->controller() == source())) + if ((network)&&(network->controller() == peer->address())) network->setNotFound(); } break; @@ -154,7 +156,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr case Packet::ERROR_NETWORK_ACCESS_DENIED_: { SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); - if ((network)&&(network->controller() == source())) + if ((network)&&(network->controller() == peer->address())) network->setAccessDenied(); } break; @@ -170,9 +172,9 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr 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()); + TRACE("dropped ERROR from %s(%s): unexpected exception: %s",peer->address().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: (unknown)",peer->address().toString().c_str(),_remoteAddress.toString().c_str()); } return true; } @@ -187,36 +189,29 @@ 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(ZT_PROTO_VERB_HELLO_IDX_REVISION); const uint64_t timestamp = at(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; + const unsigned int destAddrPtr = ZT_PROTO_VERB_HELLO_IDX_IDENTITY + id.deserialize(*this,ZT_PROTO_VERB_HELLO_IDX_IDENTITY); + InetAddress destAddr; + if (destAddrPtr < size()) // ZeroTier One < 1.0.3 did not include this field + destAddr.deserialize(*this,destAddrPtr); 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(destAddrPtr + 4)); - break; - case ZT_PROTO_DEST_ADDRESS_TYPE_IPV6: - destAddr.set(field(destAddrPtr,16),16,at(destAddrPtr + 16)); - break; - } - } - SharedPtr peer(RR->topology->getPeer(id.address())); if (peer) { // We already have an identity with this address -- check for collisions @@ -230,7 +225,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) 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((uint64_t)pid); outp.append((unsigned char)Packet::ERROR_IDENTITY_COLLISION); outp.armor(key,true); RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); @@ -273,41 +268,23 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) // Continue at // VALID } - // VALID -- continues here + // VALID -- if we made it here, packet passed identity and authenticity checks! - peer->received(RR,_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_HELLO,0,Packet::VERB_NOP); + peer->received(RR,_localAddress,_remoteAddress,hops(),pid,Packet::VERB_HELLO,0,Packet::VERB_NOP); peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision); - bool trusted = RR->topology->isRoot(id); if (destAddr) - RR->sa->iam(id.address(),_remoteAddress,destAddr,trusted,RR->node->now()); + RR->sa->iam(id.address(),_remoteAddress,destAddr,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); - - 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; - } - + _remoteAddress.serialize(outp); outp.armor(peer->key(),true); RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); } catch (std::exception &ex) { @@ -336,18 +313,9 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p const unsigned int vRevision = at(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(destAddrPtr + 4)); - break; - case ZT_PROTO_DEST_ADDRESS_TYPE_IPV6: - destAddr.set(field(destAddrPtr,16),16,at(destAddrPtr + 16)); - break; - } - } + if ((ZT_PROTO_VERB_HELLO__OK__IDX_REVISION + 2) < size()) // ZeroTier One < 1.0.3 did not include this field + destAddr.deserialize(*this,ZT_PROTO_VERB_HELLO__OK__IDX_REVISION + 2); + printf("OK(HELLO) %s\n",destAddr.toString().c_str()); if (vProto < ZT_PROTO_VERSION_MIN) { TRACE("%s(%s): OK(HELLO) dropped, protocol version too old",source().toString().c_str(),_remoteAddress.toString().c_str()); diff --git a/node/InetAddress.hpp b/node/InetAddress.hpp index c376a032..6970e92d 100644 --- a/node/InetAddress.hpp +++ b/node/InetAddress.hpp @@ -366,7 +366,8 @@ struct InetAddress : public sockaddr_storage template inline void serialize(Buffer &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,8 +388,8 @@ struct InetAddress : public sockaddr_storage template inline unsigned int deserialize(const Buffer &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; diff --git a/node/Packet.hpp b/node/Packet.hpp index 409762c7..1413db10 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -55,13 +55,15 @@ * 3 - 0.5.0 ... 0.6.0 * * Yet another multicast redesign * * New crypto completely changes key agreement cipher - * 4 - 0.6.0 ... CURRENT + * 4 - 0.6.0 ... 1.0.6 * * New identity format based on hashcash design + * 5 - 1.0.6 ... CURRENT + * * Supports CIRCUIT_TEST and friends, otherwise compatibie w/v4 * * This isn't going to change again for a long time unless your * author wakes up again at 4am with another great idea. :P */ -#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 diff --git a/node/Peer.cpp b/node/Peer.cpp index 757f822c..15648e0f 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -170,25 +170,8 @@ 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.armor(_key,false); // HELLO is sent in the clear RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size()); } -- cgit v1.2.3 From c952fbbd8d72c7f4e295bcacfe6e5b0b448505af Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 7 Oct 2015 10:40:59 -0700 Subject: Only enable 128-bit Poly1305 on X86_64 right now. Has compilation issues on ARM, but the 64-bit version should be fine. --- node/Poly1305.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/node/Poly1305.cpp b/node/Poly1305.cpp index 0968170e..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,10 +135,10 @@ typedef struct poly1305_context { unsigned char opaque[136]; } poly1305_context; -#if defined(_MSC_VER) || defined(__GNUC__) +#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 +// 128-bit implementation for MSC and GCC from Poly1305-donna #if defined(_MSC_VER) #include -- cgit v1.2.3 From 13f14c2f4ccdb38f033a8092f0088f62d2a17348 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 7 Oct 2015 10:56:47 -0700 Subject: Kill debug line. --- node/IncomingPacket.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 6186affd..19bea243 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -315,7 +315,6 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p InetAddress destAddr; if ((ZT_PROTO_VERB_HELLO__OK__IDX_REVISION + 2) < size()) // ZeroTier One < 1.0.3 did not include this field destAddr.deserialize(*this,ZT_PROTO_VERB_HELLO__OK__IDX_REVISION + 2); - printf("OK(HELLO) %s\n",destAddr.toString().c_str()); if (vProto < ZT_PROTO_VERSION_MIN) { TRACE("%s(%s): OK(HELLO) dropped, protocol version too old",source().toString().c_str(),_remoteAddress.toString().c_str()); -- cgit v1.2.3 From 7d62dbe9f7fa620982c71f44089d319120023e26 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 7 Oct 2015 11:57:59 -0700 Subject: Tune NAT-t keepalives so that timing is better obeyed, clean up a build warning, and fix a potential source of network recursion (though harmless). --- node/Constants.hpp | 2 +- node/Network.cpp | 2 -- node/Peer.cpp | 7 +++++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/node/Constants.hpp b/node/Constants.hpp index 27c43aa7..9ab390eb 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -264,7 +264,7 @@ * 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 diff --git a/node/Network.cpp b/node/Network.cpp index 9ce58c63..46f93241 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -448,7 +448,6 @@ class _AnnounceMulticastGroupsToAll public: _AnnounceMulticastGroupsToAll(const RuntimeEnvironment *renv,Network *nw) : _now(renv->node->now()), - RR(renv), _network(nw), _rootAddresses(renv->topology->rootAddresses()), _allMulticastGroups(nw->_allMulticastGroups()) @@ -458,7 +457,6 @@ public: private: uint64_t _now; - const RuntimeEnvironment *RR; Network *_network; std::vector
_rootAddresses; std::vector _allMulticastGroups; diff --git a/node/Peer.cpp b/node/Peer.cpp index 15648e0f..111c849e 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -173,6 +173,7 @@ void Peer::attemptToContactAt(const RuntimeEnvironment *RR,const InetAddress &lo RR->identity.serialize(outp,false); atAddress.serialize(outp); outp.armor(_key,false); // HELLO is sent in the clear + RR->antiRec->logOutgoingZT(outp.data(),outp.size()); RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size()); } @@ -182,12 +183,12 @@ void Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now) 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()); + TRACE("PING %s(%s) after %llums/%llums send/receive inactivity",_id.address().toString().c_str(),bestPath->address().toString().c_str(),now - bestPath->lastSend(),now - bestPath->lastReceived()); attemptToContactAt(RR,bestPath->localAddress(),bestPath->address(),now); bestPath->sent(now); } else if (((now - bestPath->lastSend()) >= ZT_NAT_KEEPALIVE_DELAY)&&(!bestPath->reliable())) { + TRACE("NAT keepalive %s(%s) after %llums/%llums send/receive inactivity",_id.address().toString().c_str(),bestPath->address().toString().c_str(),now - bestPath->lastSend(),now - bestPath->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); } @@ -202,6 +203,8 @@ void Peer::pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_ _lastDirectPathPush = now; std::vector dps(RR->node->directPaths()); + if (dps.empty()) + return; #ifdef ZT_TRACE { -- cgit v1.2.3 From e5f168f599ba053ee5e6029387dd7ad4b95a7d28 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 7 Oct 2015 13:35:46 -0700 Subject: Add proof of work request for future DDOS mitigation use. --- node/IncomingPacket.cpp | 121 ++++++++++++++++++++++++++++++++++++++++++++++++ node/IncomingPacket.hpp | 22 +++++++++ node/Packet.cpp | 2 +- node/Packet.hpp | 102 ++++++++++++++++++++++++++++++++-------- selftest.cpp | 14 ++++++ 5 files changed, 240 insertions(+), 21 deletions(-) diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 19bea243..de901779 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -41,6 +41,8 @@ #include "Peer.hpp" #include "NetworkController.hpp" #include "SelfAwareness.hpp" +#include "Salsa20.hpp" +#include "SHA512.hpp" namespace ZeroTier { @@ -90,6 +92,7 @@ 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(sourceAddress); @@ -1042,6 +1045,124 @@ bool IncomingPacket::_doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,const S return true; } +bool IncomingPacket::_doREQUEST_PROOF_OF_WORK(const RuntimeEnvironment *RR,const SharedPtr &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 unsigned int difficulty = (*this)[ZT_PACKET_IDX_PAYLOAD + 1]; + const unsigned int challengeLength = at(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: { + unsigned char result[16]; + computeSalsa2012Sha512ProofOfWork(difficulty,challenge,challengeLength,result); + + Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); + outp.append((unsigned char)Packet::VERB_REQUEST_PROOF_OF_WORK); + outp.append(packetId()); + outp.append((uint16_t)sizeof(result)); + outp.append(result,sizeof(result)); + outp.armor(peer->key(),true); + RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); + } break; + + default: + TRACE("dropped REQUEST_PROO_OF_WORK from %s(%s): unrecognized proof of work type",peer->address().toString().c_str(),_remoteAddress.toString().c_str()); + break; + } + } else { + TRACE("dropped REQUEST_PROO_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(candidate)); + + SHA512::hash(shabuf,candidate,16 + challengeLength); + s20.init(shabuf,256,&s20iv,12); + memset(salsabuf,0,sizeof(salsabuf)); + s20.encrypt(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,12); + memset(salsabuf,0,sizeof(salsabuf)); + s20.encrypt(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; +} + void IncomingPacket::_sendErrorNeedCertificate(const RuntimeEnvironment *RR,const SharedPtr &peer,uint64_t nwid) { Packet outp(source(),RR->identity.address(),Packet::VERB_ERROR); diff --git a/node/IncomingPacket.hpp b/node/IncomingPacket.hpp index 06220c4b..fd7a06c0 100644 --- a/node/IncomingPacket.hpp +++ b/node/IncomingPacket.hpp @@ -107,6 +107,27 @@ public: */ 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. @@ -126,6 +147,7 @@ private: bool _doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const SharedPtr &peer); bool _doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPtr &peer); bool _doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,const SharedPtr &peer); + bool _doREQUEST_PROOF_OF_WORK(const RuntimeEnvironment *RR,const SharedPtr &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,uint64_t nwid); diff --git a/node/Packet.cpp b/node/Packet.cpp index f69e4e79..2d973dff 100644 --- a/node/Packet.cpp +++ b/node/Packet.cpp @@ -45,7 +45,6 @@ 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_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 +55,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)"; } diff --git a/node/Packet.hpp b/node/Packet.hpp index 1413db10..93b594e5 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -523,10 +523,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> @@ -564,7 +567,8 @@ public: */ VERB_HELLO = 1, - /* Error response: + /** + * Error response: * <[1] in-re verb> * <[8] in-re packet ID> * <[1] error code> @@ -572,14 +576,16 @@ 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: @@ -590,7 +596,8 @@ public: */ 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> @@ -613,7 +620,8 @@ public: */ 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> @@ -628,7 +636,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>] @@ -652,9 +661,10 @@ public: VERB_EXT_FRAME = 7, /* DEPRECATED */ - VERB_P5_MULTICAST_FRAME = 8, + //VERB_P5_MULTICAST_FRAME = 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)> @@ -667,7 +677,8 @@ public: */ VERB_MULTICAST_LIKE = 9, - /* Network member certificate replication/push: + /** + * Network member certificate replication/push: * <[...] serialized certificate of membership> * [ ... additional certificates may follow ...] * @@ -678,7 +689,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> @@ -713,7 +725,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 @@ -724,7 +737,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> @@ -762,7 +776,8 @@ public: */ VERB_MULTICAST_GATHER = 13, - /* Multicast frame: + /** + * Multicast frame: * <[8] 64-bit network ID> * <[1] flags> * [<[...] network certificate of membership>] @@ -803,7 +818,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> @@ -859,7 +875,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> * @@ -899,7 +916,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> @@ -977,7 +995,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)> @@ -1010,7 +1029,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 }; /** diff --git a/selftest.cpp b/selftest.cpp index e938cf4d..090839ee 100644 --- a/selftest.cpp +++ b/selftest.cpp @@ -52,6 +52,7 @@ #include "node/CertificateOfMembership.hpp" #include "node/Defaults.hpp" #include "node/Node.hpp" +#include "node/IncomingPacket.hpp" #include "osdep/OSUtils.hpp" #include "osdep/Phy.hpp" @@ -285,6 +286,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 Date: Wed, 7 Oct 2015 13:46:44 -0700 Subject: Limit proof of work difficulty to something sane. --- node/IncomingPacket.cpp | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index de901779..cfe5a6c3 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -1060,24 +1060,33 @@ bool IncomingPacket::_doREQUEST_PROOF_OF_WORK(const RuntimeEnvironment *RR,const // Salsa20/12+SHA512 hashcash case 0x01: { - unsigned char result[16]; - computeSalsa2012Sha512ProofOfWork(difficulty,challenge,challengeLength,result); - - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); - outp.append((unsigned char)Packet::VERB_REQUEST_PROOF_OF_WORK); - outp.append(packetId()); - outp.append((uint16_t)sizeof(result)); - outp.append(result,sizeof(result)); - outp.armor(peer->key(),true); - RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); + 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(result))),Utils::ntoh(*(reinterpret_cast(result + 8)))); + Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); + outp.append((unsigned char)Packet::VERB_REQUEST_PROOF_OF_WORK); + outp.append(packetId()); + outp.append((uint16_t)sizeof(result)); + outp.append(result,sizeof(result)); + outp.armor(peer->key(),true); + 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(packetId()); + outp.append((unsigned char)Packet::ERROR_INVALID_REQUEST); + outp.armor(peer->key(),true); + RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); + } } break; default: - TRACE("dropped REQUEST_PROO_OF_WORK from %s(%s): unrecognized proof of work type",peer->address().toString().c_str(),_remoteAddress.toString().c_str()); + TRACE("dropped REQUEST_PROOF_OF_WORK from %s(%s): unrecognized proof of work type",peer->address().toString().c_str(),_remoteAddress.toString().c_str()); break; } } else { - TRACE("dropped REQUEST_PROO_OF_WORK from %s(%s): not trusted enough",peer->address().toString().c_str(),_remoteAddress.toString().c_str()); + 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()); -- cgit v1.2.3 From 69b44bf9a56ea742e05035f31660fbb23762df1b Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 7 Oct 2015 16:11:50 -0700 Subject: Finally add an ECHO. --- node/IncomingPacket.cpp | 15 ++++++++++++++- node/IncomingPacket.hpp | 1 + node/Packet.cpp | 1 + node/Packet.hpp | 28 ++++++++++++++++------------ 4 files changed, 32 insertions(+), 13 deletions(-) diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index cfe5a6c3..083c47f8 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -83,6 +83,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) 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); @@ -569,6 +570,18 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

&peer) +{ + try { + Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); + outp.append((unsigned char)Packet::VERB_ECHO); + outp.append(packetId()); + outp.append(field(ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD),size() - ZT_PACKET_IDX_PAYLOAD); + RR->sw->send(outp,true,0); + } catch ( ... ) {} + return true; +} + bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,const SharedPtr &peer) { try { @@ -636,7 +649,7 @@ 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->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); diff --git a/node/IncomingPacket.hpp b/node/IncomingPacket.hpp index fd7a06c0..f5dd4b27 100644 --- a/node/IncomingPacket.hpp +++ b/node/IncomingPacket.hpp @@ -138,6 +138,7 @@ private: bool _doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr &peer); bool _doFRAME(const RuntimeEnvironment *RR,const SharedPtr &peer); bool _doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr &peer); + bool _doECHO(const RuntimeEnvironment *RR,const SharedPtr &peer); bool _doMULTICAST_LIKE(const RuntimeEnvironment *RR,const SharedPtr &peer); bool _doNETWORK_MEMBERSHIP_CERTIFICATE(const RuntimeEnvironment *RR,const SharedPtr &peer); bool _doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,const SharedPtr &peer); diff --git a/node/Packet.cpp b/node/Packet.cpp index 2d973dff..2fb7d488 100644 --- a/node/Packet.cpp +++ b/node/Packet.cpp @@ -45,6 +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_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"; diff --git a/node/Packet.hpp b/node/Packet.hpp index 93b594e5..01aadad0 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -46,22 +46,20 @@ #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 + * + 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 + * + New identity format based on hashcash design * 5 - 1.0.6 ... CURRENT - * * Supports CIRCUIT_TEST and friends, otherwise compatibie w/v4 - * - * This isn't going to change again for a long time unless your - * author wakes up again at 4am with another great idea. :P + * + Supports circuit test, proof of work, and echo + * + Otherwise backward compatible with 4 */ #define ZT_PROTO_VERSION 5 @@ -660,8 +658,14 @@ 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. + */ + VERB_ECHO = 8, /** * Announce interest in multicast group(s): -- cgit v1.2.3 From 0ce0bc00d220ba67af03bf0cc01c8fe9f9104039 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 7 Oct 2015 16:20:54 -0700 Subject: Make sure received() gets called for some new messages, and docs. --- node/IncomingPacket.cpp | 17 +++++++++++++---- node/Packet.hpp | 2 ++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 083c47f8..4dd308cd 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -573,11 +573,13 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

&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(packetId()); + outp.append((uint64_t)pid); outp.append(field(ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD),size() - ZT_PACKET_IDX_PAYLOAD); - RR->sw->send(outp,true,0); + RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); + peer->received(RR,_localAddress,_remoteAddress,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP); } catch ( ... ) {} return true; } @@ -881,6 +883,8 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha } ptr += addrLen; } + + peer->received(RR,_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP); } 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()); } catch ( ... ) { @@ -1045,6 +1049,8 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt RR->sw->send(outp,true,originatorCredentialNetworkId); } } + + peer->received(RR,_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP); } catch (std::exception &exc) { TRACE("dropped CIRCUIT_TEST from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),exc.what()); } catch ( ... ) { @@ -1063,6 +1069,7 @@ bool IncomingPacket::_doREQUEST_PROOF_OF_WORK(const RuntimeEnvironment *RR,const 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(ZT_PACKET_IDX_PAYLOAD + 2); if (challengeLength > ZT_PROTO_MAX_PACKET_LENGTH) @@ -1079,7 +1086,7 @@ bool IncomingPacket::_doREQUEST_PROOF_OF_WORK(const RuntimeEnvironment *RR,const 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(result))),Utils::ntoh(*(reinterpret_cast(result + 8)))); Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); outp.append((unsigned char)Packet::VERB_REQUEST_PROOF_OF_WORK); - outp.append(packetId()); + outp.append(pid); outp.append((uint16_t)sizeof(result)); outp.append(result,sizeof(result)); outp.armor(peer->key(),true); @@ -1087,7 +1094,7 @@ bool IncomingPacket::_doREQUEST_PROOF_OF_WORK(const RuntimeEnvironment *RR,const } else { Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR); outp.append((unsigned char)Packet::VERB_REQUEST_PROOF_OF_WORK); - outp.append(packetId()); + outp.append(pid); outp.append((unsigned char)Packet::ERROR_INVALID_REQUEST); outp.armor(peer->key(),true); RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); @@ -1098,6 +1105,8 @@ bool IncomingPacket::_doREQUEST_PROOF_OF_WORK(const RuntimeEnvironment *RR,const 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()); } diff --git a/node/Packet.hpp b/node/Packet.hpp index 01aadad0..6f3cb72f 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -664,6 +664,8 @@ public: * * This generates OK with a copy of the transmitted payload. No ERROR * is generated. Response to ECHO requests is optional. + * + * Note that fragmented ECHO packets may not work. */ VERB_ECHO = 8, -- cgit v1.2.3 From fea1b6b2c3d004ad53c5997800229c070ccee79b Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 7 Oct 2015 16:25:08 -0700 Subject: docs --- node/Packet.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/node/Packet.hpp b/node/Packet.hpp index 6f3cb72f..1c7a6f5e 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -365,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 -- cgit v1.2.3 From 9347d6c866f6cae357448762f064a481fb765c00 Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Wed, 7 Oct 2015 18:04:40 -0700 Subject: Make it so ZeroTierOne.h can be used with a C compiler again. --- include/ZeroTierOne.h | 4 ++-- node/Node.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 990f682d..175cedc5 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -1255,7 +1255,7 @@ void ZT_Node_freeQueryResult(ZT_Node *node,void *qr); * @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,int metric, enum ZT_LocalInterfaceAddressTrust trust); /** * Clear local interface addresses @@ -1296,7 +1296,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 diff --git a/node/Node.cpp b/node/Node.cpp index d5ca147c..7f469b97 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -779,7 +779,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(node)->circuitTestBegin(test,reportCallback); @@ -795,7 +795,7 @@ 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) +int ZT_Node_addLocalInterfaceAddress(ZT_Node *node,const struct sockaddr_storage *addr,int metric, enum ZT_LocalInterfaceAddressTrust trust) { try { return reinterpret_cast(node)->addLocalInterfaceAddress(addr,metric,trust); -- cgit v1.2.3 From 273f0d18b0bc907d90e746f5836576150f4cde22 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 8 Oct 2015 09:05:25 -0700 Subject: docs --- node/Packet.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/node/Packet.hpp b/node/Packet.hpp index 1c7a6f5e..4dfa73f0 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -345,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 ...] -- cgit v1.2.3 From a3876353ca1cb07213c5e1c5208b531caeda5523 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 8 Oct 2015 13:25:38 -0700 Subject: Abiltiy to post a test via the controller web API, and parsing of CIRCUIT_TEST_REPORT messages. --- controller/SqliteNetworkController.cpp | 50 ++++++++++++++++++ controller/SqliteNetworkController.hpp | 8 +++ node/IncomingPacket.cpp | 94 +++++++++++++++++++--------------- 3 files changed, 111 insertions(+), 41 deletions(-) diff --git a/controller/SqliteNetworkController.cpp b/controller/SqliteNetworkController.cpp index 334ccc75..861cdbcf 100644 --- a/controller/SqliteNetworkController.cpp +++ b/controller/SqliteNetworkController.cpp @@ -505,6 +505,52 @@ 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;ku.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;kku.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;kkku.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(); + _node->circuitTestBegin(test,&(SqliteNetworkController::_circuitTestCallback)); + + return 200; } // else 404 } else { @@ -1819,4 +1865,8 @@ NetworkController::ResultCode SqliteNetworkController::_doNetworkConfigRequest(c return NetworkController::NETCONF_QUERY_OK; } +static void _circuitTestCallback(ZT_Node *node,ZT_CircuitTest *test,const ZT_CircuitTestReport *report) +{ +} + } // namespace ZeroTier diff --git a/controller/SqliteNetworkController.hpp b/controller/SqliteNetworkController.hpp index 68529e39..7a01487c 100644 --- a/controller/SqliteNetworkController.hpp +++ b/controller/SqliteNetworkController.hpp @@ -43,6 +43,9 @@ // 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; @@ -106,6 +109,8 @@ private: const Dictionary &metaData, Dictionary &netconf); + static void _circuitTestCallback(ZT_Node *node,ZT_CircuitTest *test,const ZT_CircuitTestReport *report); + Node *_node; std::string _dbPath; std::string _circuitTestPath; @@ -140,6 +145,9 @@ private: // Last log entries by address and network ID pair std::map< std::pair,_LLEntry > _lastLog; + // Circuit tests outstanding + std::map< uint64_t,ZT_CircuitTest * > _circuitTests; + sqlite3 *_db; sqlite3_stmt *_sGetNetworkById; diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 4dd308cd..0aadc104 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -175,10 +175,8 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr } 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",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),ex.what()); } catch ( ... ) { - TRACE("dropped ERROR from %s(%s): unexpected exception: (unknown)",peer->address().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; } @@ -291,8 +289,6 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) _remoteAddress.serialize(outp); outp.armor(peer->key(),true); 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()); } catch ( ... ) { TRACE("dropped HELLO from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); } @@ -395,10 +391,8 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &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; } @@ -453,8 +447,6 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr< } 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()); } - } 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()); } @@ -487,10 +479,8 @@ bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,const SharedPtr } else { TRACE("dropped FRAME from %s(%s): we are not connected to network %.16llx",source().toString().c_str(),_remoteAddress.toString().c_str(),at(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; } @@ -562,10 +552,8 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

(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; } @@ -580,7 +568,9 @@ bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,const SharedPtr outp.append(field(ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD),size() - ZT_PACKET_IDX_PAYLOAD); RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); peer->received(RR,_localAddress,_remoteAddress,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP); - } catch ( ... ) {} + } catch ( ... ) { + TRACE("dropped ECHO from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); + } return true; } @@ -594,10 +584,8 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,const Shared RR->mc->add(now,at(ptr),MulticastGroup(MAC(field(ptr + 8,6),6),at(ptr + 14)),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; } @@ -614,10 +602,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; } @@ -700,10 +686,8 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons outp.armor(peer->key(),true); 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; } @@ -720,10 +704,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; } @@ -751,10 +733,8 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const Shar } 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; } @@ -842,10 +822,8 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share } // 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; } @@ -885,10 +863,8 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha } peer->received(RR,_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP); - } 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()); } 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; } @@ -1051,16 +1027,52 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt } peer->received(RR,_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP); - } catch (std::exception &exc) { - TRACE("dropped CIRCUIT_TEST from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),exc.what()); } 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) { + try { + ZT_CircuitTestReport report; + memset(&report,0,sizeof(report)); + + report.address = peer->address().toInt(); + report.testId = at(ZT_PACKET_IDX_PAYLOAD + 8); + report.timestamp = at(ZT_PACKET_IDX_PAYLOAD); + report.remoteTimestamp = at(ZT_PACKET_IDX_PAYLOAD + 16); + report.sourcePacketId = at(ZT_PACKET_IDX_PAYLOAD + 44); + report.flags = at(ZT_PACKET_IDX_PAYLOAD + 36); + report.sourcePacketHopCount = (*this)[ZT_PACKET_IDX_PAYLOAD + 52]; + report.errorCode = at(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(ZT_PACKET_IDX_PAYLOAD + 28); + report.platform = (enum ZT_Platform)at(ZT_PACKET_IDX_PAYLOAD + 30); + report.architecture = (enum ZT_Architecture)at(ZT_PACKET_IDX_PAYLOAD + 32); + + const unsigned int receivedOnLocalAddressLen = reinterpret_cast(&(report.receivedOnLocalAddress))->deserialize(*this,ZT_PACKET_IDX_PAYLOAD + 53); + const unsigned int receivedFromRemoteAddressLen = reinterpret_cast(&(report.receivedFromRemoteAddress))->deserialize(*this,ZT_PACKET_IDX_PAYLOAD + 53 + receivedOnLocalAddressLen); + + unsigned int nhptr = ZT_PACKET_IDX_PAYLOAD + 53 + receivedOnLocalAddressLen + receivedFromRemoteAddressLen; + nhptr += at(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(nhptr); nhptr += 8; + nhptr += reinterpret_cast(&(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; } -- cgit v1.2.3 From 59da8b2a4b3e36605886944f3fa111870bbb8a2c Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 8 Oct 2015 15:44:06 -0700 Subject: Logging of circuit test results to disk. --- controller/SqliteNetworkController.cpp | 72 ++++++++++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 3 deletions(-) diff --git a/controller/SqliteNetworkController.cpp b/controller/SqliteNetworkController.cpp index 861cdbcf..13a0cadd 100644 --- a/controller/SqliteNetworkController.cpp +++ b/controller/SqliteNetworkController.cpp @@ -524,8 +524,8 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpPOST( json_value *hop = j->u.object.values[k].value->u.array.values[kk]; if (hop->type == json_array) { for(unsigned int kkk=0;kkku.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; + 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; @@ -548,6 +548,7 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpPOST( } test->timestamp = OSUtils::now(); + _circuitTests[test->testId] = test; _node->circuitTestBegin(test,&(SqliteNetworkController::_circuitTestCallback)); return 200; @@ -1865,8 +1866,73 @@ NetworkController::ResultCode SqliteNetworkController::_doNetworkConfigRequest(c return NetworkController::NETCONF_QUERY_OK; } -static void _circuitTestCallback(ZT_Node *node,ZT_CircuitTest *test,const ZT_CircuitTestReport *report) +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(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"%.10llx",report->address); + 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\"address\": \"%.10llx\","ZT_EOL_S + "\t\"testId\": \"%.16llx\","ZT_EOL_S + "\t\"timestamp\": %llu,"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" : ""), + report->address, + test->testId, + report->timestamp, + now, + report->remoteTimestamp, + report->sourcePacketId, + 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(&(report->receivedOnLocalAddress))->toString().c_str(), + reinterpret_cast(&(report->receivedFromRemoteAddress))->toString().c_str()); + fclose(f); + } } } // namespace ZeroTier -- cgit v1.2.3 From 160278c489b8ec2f11235f839836f0f014990fda Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 8 Oct 2015 17:42:53 -0700 Subject: Little bit of reorg in Salsa20 which seems to speed things up very slightly. --- node/Salsa20.cpp | 75 ++++++++++++++++++++------------------------------------ 1 file changed, 26 insertions(+), 49 deletions(-) diff --git a/node/Salsa20.cpp b/node/Salsa20.cpp index f8cf8591..dec14faf 100644 --- a/node/Salsa20.cpp +++ b/node/Salsa20.cpp @@ -175,41 +175,34 @@ 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(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(X2, _mm_slli_epi32(T, 9)); - X2 = _mm_xor_si128(X2, _mm_srli_epi32(T, 23)); + 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(X3, _mm_slli_epi32(T, 13)); - X3 = _mm_xor_si128(X3, _mm_srli_epi32(T, 19)); + 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(X0, _mm_slli_epi32(T, 18)); - X0 = _mm_xor_si128(X0, _mm_srli_epi32(T, 14)); + 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(X3, _mm_slli_epi32(T, 7)); - X3 = _mm_xor_si128(X3, _mm_srli_epi32(T, 25)); + 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(X2, _mm_slli_epi32(T, 9)); - X2 = _mm_xor_si128(X2, _mm_srli_epi32(T, 23)); + 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(X1, _mm_slli_epi32(T, 13)); - X1 = _mm_xor_si128(X1, _mm_srli_epi32(T, 19)); + 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(X0, _mm_slli_epi32(T, 18)); - X0 = _mm_xor_si128(X0, _mm_srli_epi32(T, 14)); + 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); @@ -218,34 +211,26 @@ void Salsa20::encrypt(const void *in,void *out,unsigned int bytes) // -- 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)); + 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(X2, _mm_slli_epi32(T, 9)); - X2 = _mm_xor_si128(X2, _mm_srli_epi32(T, 23)); + 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(X3, _mm_slli_epi32(T, 13)); - X3 = _mm_xor_si128(X3, _mm_srli_epi32(T, 19)); + 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(X0, _mm_slli_epi32(T, 18)); - X0 = _mm_xor_si128(X0, _mm_srli_epi32(T, 14)); + 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(X3, _mm_slli_epi32(T, 7)); - X3 = _mm_xor_si128(X3, _mm_srli_epi32(T, 25)); + 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(X2, _mm_slli_epi32(T, 9)); - X2 = _mm_xor_si128(X2, _mm_srli_epi32(T, 23)); + 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(X1, _mm_slli_epi32(T, 13)); - X1 = _mm_xor_si128(X1, _mm_srli_epi32(T, 19)); + 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(X0, _mm_slli_epi32(T, 18)); - X0 = _mm_xor_si128(X0, _mm_srli_epi32(T, 14)); + 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); @@ -257,22 +242,14 @@ void Salsa20::encrypt(const void *in,void *out,unsigned int bytes) 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(c),_mm_castsi128_ps(_mm_xor_si128(_mm_unpackhi_epi64(k02,k20),_mm_castps_si128(_mm_loadu_ps(reinterpret_cast(m)))))); + _mm_storeu_ps(reinterpret_cast(c) + 4,_mm_castsi128_ps(_mm_xor_si128(_mm_unpackhi_epi64(k13,k31),_mm_castps_si128(_mm_loadu_ps(reinterpret_cast(m) + 4))))); + _mm_storeu_ps(reinterpret_cast(c) + 8,_mm_castsi128_ps(_mm_xor_si128(_mm_unpacklo_epi64(k20,k02),_mm_castps_si128(_mm_loadu_ps(reinterpret_cast(m) + 8))))); + _mm_storeu_ps(reinterpret_cast(c) + 12,_mm_castsi128_ps(_mm_xor_si128(_mm_unpacklo_epi64(k31,k13),_mm_castps_si128(_mm_loadu_ps(reinterpret_cast(m) + 12))))); if (!(++_state.i[8])) { ++_state.i[5]; // state reordered for SSE -- cgit v1.2.3 From 3fa6dd377f479774ae2726f24748f41458329272 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 9 Oct 2015 08:51:57 -0700 Subject: docs --- node/Packet.hpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/node/Packet.hpp b/node/Packet.hpp index 4dfa73f0..5c7253bf 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -669,7 +669,8 @@ public: * This generates OK with a copy of the transmitted payload. No ERROR * is generated. Response to ECHO requests is optional. * - * Note that fragmented ECHO packets may not work. + * Support for fragmented echo packets is optional and their use is not + * recommended. */ VERB_ECHO = 8, @@ -680,8 +681,18 @@ public: * <[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. */ -- cgit v1.2.3 From 0c498556d5b11c101d2b18cf85cff2d53aa97d58 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 9 Oct 2015 09:39:27 -0700 Subject: Unroll Salsa20 fully for a little more speed (non-SSE now almost as fast as SSE) --- node/Identity.cpp | 9 +- node/IncomingPacket.cpp | 8 +- node/Node.cpp | 6 +- node/Packet.cpp | 12 +- node/Salsa20.cpp | 1206 ++++++++++++++++++++++++++++++++++++++++++----- node/Salsa20.hpp | 40 +- selftest.cpp | 42 +- 7 files changed, 1138 insertions(+), 185 deletions(-) diff --git a/node/Identity.cpp b/node/Identity.cpp index 8765da51..e5aaf13d 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(candidate)); SHA512::hash(shabuf,candidate,16 + challengeLength); - s20.init(shabuf,256,&s20iv,12); + s20.init(shabuf,256,&s20iv); memset(salsabuf,0,sizeof(salsabuf)); - s20.encrypt(salsabuf,salsabuf,sizeof(salsabuf)); + s20.encrypt12(salsabuf,salsabuf,sizeof(salsabuf)); SHA512::hash(shabuf,salsabuf,sizeof(salsabuf)); d = difficulty; @@ -1186,9 +1186,9 @@ bool IncomingPacket::testSalsa2012Sha512ProofOfWorkResult(unsigned int difficult memcpy(candidate + 16,challenge,challengeLength); SHA512::hash(shabuf,candidate,16 + challengeLength); - s20.init(shabuf,256,&s20iv,12); + s20.init(shabuf,256,&s20iv); memset(salsabuf,0,sizeof(salsabuf)); - s20.encrypt(salsabuf,salsabuf,sizeof(salsabuf)); + s20.encrypt12(salsabuf,salsabuf,sizeof(salsabuf)); SHA512::hash(shabuf,salsabuf,sizeof(salsabuf)); d = difficulty; diff --git a/node/Node.cpp b/node/Node.cpp index 7f469b97..84452146 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -88,9 +88,9 @@ Node::Node( { 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")); @@ -574,7 +574,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]; } diff --git a/node/Packet.cpp b/node/Packet.cpp index 2fb7d488..f11ae1b8 100644 --- a/node/Packet.cpp +++ b/node/Packet.cpp @@ -92,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); @@ -116,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/Salsa20.cpp b/node/Salsa20.cpp index dec14faf..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]; @@ -181,61 +179,149 @@ void Salsa20::encrypt(const void *in,void *out,unsigned int bytes) __m128i X2s = X2; __m128i X3s = X3; - for (i=0;i<_roundsDiv4;++i) { - 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); - - // -- - - 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); @@ -273,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(c),_mm_castsi128_ps(_mm_xor_si128(_mm_unpackhi_epi64(k02,k20),_mm_castps_si128(_mm_loadu_ps(reinterpret_cast(m)))))); + _mm_storeu_ps(reinterpret_cast(c) + 4,_mm_castsi128_ps(_mm_xor_si128(_mm_unpackhi_epi64(k13,k31),_mm_castps_si128(_mm_loadu_ps(reinterpret_cast(m) + 4))))); + _mm_storeu_ps(reinterpret_cast(c) + 8,_mm_castsi128_ps(_mm_xor_si128(_mm_unpacklo_epi64(k20,k02),_mm_castps_si128(_mm_loadu_ps(reinterpret_cast(m) + 8))))); + _mm_storeu_ps(reinterpret_cast(c) + 12,_mm_castsi128_ps(_mm_xor_si128(_mm_unpacklo_epi64(k31,k13),_mm_castps_si128(_mm_loadu_ps(reinterpret_cast(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..a2082bea 100644 --- a/node/Salsa20.hpp +++ b/node/Salsa20.hpp @@ -35,12 +35,11 @@ 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 */ - 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,21 +48,43 @@ 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 + * Encrypt data using Salsa20/12 * * @param in Input data * @param out Output buffer * @param bytes Length of data */ - void encrypt(const void *in,void *out,unsigned int bytes) + void encrypt12(const void *in,void *out,unsigned int bytes) throw(); + /** + * Encrypt data using Salsa20/20 + * + * @param in Input data + * @param out Output buffer + * @param bytes Length of data + */ + void encrypt20(const void *in,void *out,unsigned int bytes) + throw(); + + /** + * Decrypt data + * + * @param in Input data + * @param out Output buffer + * @param bytes Length of data + */ + inline void decrypt12(const void *in,void *out,unsigned int bytes) + throw() + { + encrypt12(in,out,bytes); + } + /** * Decrypt data * @@ -71,10 +92,10 @@ public: * @param out Output buffer * @param bytes Length of data */ - inline void decrypt(const void *in,void *out,unsigned int bytes) + inline void decrypt20(const void *in,void *out,unsigned int bytes) throw() { - encrypt(in,out,bytes); + encrypt20(in,out,bytes); } private: @@ -84,7 +105,6 @@ private: #endif // ZT_SALSA20_SSE uint32_t i[16]; } _state; - unsigned int _roundsDiv4; }; } // namespace ZeroTier diff --git a/selftest.cpp b/selftest.cpp index 090839ee..4ba76c0b 100644 --- a/selftest.cpp +++ b/selftest.cpp @@ -162,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; @@ -195,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(); @@ -236,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(); -- cgit v1.2.3 From c2bbec2f050da996f660f2ae28b365330ebff633 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 9 Oct 2015 10:14:20 -0700 Subject: Docker example (and useful for testing) --- .gitignore | 2 ++ examples/docker/Dockerfile | 19 +++++++++++++++++++ examples/docker/README.md | 8 ++++++++ examples/docker/main.sh | 25 +++++++++++++++++++++++++ 4 files changed, 54 insertions(+) create mode 100644 examples/docker/Dockerfile create mode 100644 examples/docker/README.md create mode 100644 examples/docker/main.sh diff --git a/.gitignore b/.gitignore index 498119e3..b5d71690 100755 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,8 @@ Thumbs.db # *nix/Mac build droppings /build-* /ZeroTierOneInstaller-* +/examples/docker/zerotier-one +/examples/docker/test-*.env # Miscellaneous file types that we don't want to check in *.log diff --git a/examples/docker/Dockerfile b/examples/docker/Dockerfile new file mode 100644 index 00000000..a4274924 --- /dev/null +++ b/examples/docker/Dockerfile @@ -0,0 +1,19 @@ +FROM centos:7 + +MAINTAINER https://www.zerotier.com/ + +RUN yum -y update && 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..4dae52f3 --- /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 --cap-add=NET_ADMIN". 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..e9febb13 --- /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" >identity.secret + +/var/lib/zerotier-one/zerotier-one -- cgit v1.2.3 From 9a2565115119f4c56bada376974ed77c6b2661c7 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 9 Oct 2015 10:14:45 -0700 Subject: . --- examples/docker/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/docker/README.md b/examples/docker/README.md index 4dae52f3..fbc93481 100644 --- a/examples/docker/README.md +++ b/examples/docker/README.md @@ -5,4 +5,4 @@ This is a simple Docker example using ZeroTier One in normal tun/tap mode. It us 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 --cap-add=NET_ADMIN". The main.sh script supplied here will complain and exit if these options are not present (no /dev/net/tun device). +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). -- cgit v1.2.3 From e33adad8f5b1bb64cc4c5b318a8fb95077407419 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 9 Oct 2015 12:15:42 -0700 Subject: Script to quickly generate test docker env files. --- examples/docker/maketestenv.sh | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100755 examples/docker/maketestenv.sh 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 ' + exit 1 +fi + +newid=`../../zerotier-idtool generate` + +echo "ZEROTIER_IDENTITY_SECRET=$newid" >$1 +echo "ZEROTIER_NETWORK=$2" >>$1 -- cgit v1.2.3 From 6b5bb0b27874b3005964deaca347289e583899f8 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 9 Oct 2015 12:22:13 -0700 Subject: Eliminate format string warnings. --- controller/SqliteNetworkController.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/controller/SqliteNetworkController.cpp b/controller/SqliteNetworkController.cpp index 13a0cadd..40fafd79 100644 --- a/controller/SqliteNetworkController.cpp +++ b/controller/SqliteNetworkController.cpp @@ -1913,13 +1913,13 @@ void SqliteNetworkController::_circuitTestCallback(ZT_Node *node,ZT_CircuitTest "\t\"receivedFromRemoteAddress\": \"%s\""ZT_EOL_S "}", ((ftell(f) > 0) ? ",\n" : ""), - report->address, - test->testId, - report->timestamp, - now, - report->remoteTimestamp, - report->sourcePacketId, - report->flags, + (unsigned long long)report->address, + (unsigned long long)test->testId, + (unsigned long long)report->timestamp, + (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, -- cgit v1.2.3 From 97dee9de36a69ed0aba4baf0cce03b9c4f11b30d Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 9 Oct 2015 12:50:52 -0700 Subject: Add more helpful example stuff. --- examples/api/README.md | 20 ++++++++++++++++++++ examples/api/public.json | 27 +++++++++++++++++++++++++++ examples/docker/Dockerfile | 2 +- 3 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 examples/api/README.md create mode 100644 examples/api/public.json diff --git a/examples/api/README.md b/examples/api/README.md new file mode 100644 index 00000000..8b6d9633 --- /dev/null +++ b/examples/api/README.md @@ -0,0 +1,20 @@ +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. 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 index a4274924..f1ce6bb5 100644 --- a/examples/docker/Dockerfile +++ b/examples/docker/Dockerfile @@ -2,7 +2,7 @@ FROM centos:7 MAINTAINER https://www.zerotier.com/ -RUN yum -y update && yum clean all +RUN yum -y update && yum install -y sqlite net-tools && yum clean all EXPOSE 9993/udp -- cgit v1.2.3 From a95fa379cca0ddbce98d476b143c3606f3ae7bce Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 9 Oct 2015 14:51:38 -0700 Subject: Circuit tests basically work but need some tweaks, and fix some issues found with valgrind. --- controller/SqliteNetworkController.cpp | 2 - controller/SqliteNetworkController.hpp | 2 - examples/api/circuit-test-pingpong.json | 13 ++++++ examples/docker/main.sh | 2 +- node/InetAddress.hpp | 72 ++++++++++++++++++++------------- node/Node.cpp | 2 +- 6 files changed, 59 insertions(+), 34 deletions(-) create mode 100644 examples/api/circuit-test-pingpong.json diff --git a/controller/SqliteNetworkController.cpp b/controller/SqliteNetworkController.cpp index 40fafd79..d87e5624 100644 --- a/controller/SqliteNetworkController.cpp +++ b/controller/SqliteNetworkController.cpp @@ -258,8 +258,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); diff --git a/controller/SqliteNetworkController.hpp b/controller/SqliteNetworkController.hpp index 7a01487c..a3d5dfc7 100644 --- a/controller/SqliteNetworkController.hpp +++ b/controller/SqliteNetworkController.hpp @@ -155,8 +155,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/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/docker/main.sh b/examples/docker/main.sh index e9febb13..53fb6540 100644 --- a/examples/docker/main.sh +++ b/examples/docker/main.sh @@ -20,6 +20,6 @@ else fi rm -f /var/lib/zerotier-one/identity.* -echo "$ZEROTIER_IDENTITY_SECRET" >identity.secret +echo "$ZEROTIER_IDENTITY_SECRET" >/var/lib/zerotier-one/identity.secret /var/lib/zerotier-one/zerotier-one diff --git a/node/InetAddress.hpp b/node/InetAddress.hpp index 6970e92d..50db272a 100644 --- a/node/InetAddress.hpp +++ b/node/InetAddress.hpp @@ -100,74 +100,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(&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(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(&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(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(&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(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(&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 +189,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(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; } diff --git a/node/Node.cpp b/node/Node.cpp index 84452146..1eb21914 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -491,7 +491,7 @@ ZT_ResultCode Node::circuitTestBegin(ZT_CircuitTest *test,void (*reportCallback) for(unsigned int a=0;ahops[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 -- cgit v1.2.3 From aec13b50fdbb210e25c9bcfcb8f902da842ac65f Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 9 Oct 2015 15:05:26 -0700 Subject: Be a bit more verbose in circuit test reports to more clearly track current and upstream hop in graph traversal history. --- controller/SqliteNetworkController.cpp | 8 +++++--- include/ZeroTierOne.h | 9 +++++++-- node/IncomingPacket.cpp | 12 +++++++----- node/Packet.hpp | 1 + 4 files changed, 20 insertions(+), 10 deletions(-) diff --git a/controller/SqliteNetworkController.cpp b/controller/SqliteNetworkController.cpp index d87e5624..08bd3a15 100644 --- a/controller/SqliteNetworkController.cpp +++ b/controller/SqliteNetworkController.cpp @@ -1881,7 +1881,7 @@ void SqliteNetworkController::_circuitTestCallback(ZT_Node *node,ZT_CircuitTest 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"%.10llx",report->address); + Utils::snprintf(tmp,sizeof(tmp),ZT_PATH_SEPARATOR_S"%.10llx_%.10llx",report->upstream,report->current); reportSavePath.append(tmp); { @@ -1891,7 +1891,8 @@ void SqliteNetworkController::_circuitTestCallback(ZT_Node *node,ZT_CircuitTest return; fseek(f,0,SEEK_END); fprintf(f,"%s{\n" - "\t\"address\": \"%.10llx\","ZT_EOL_S + "\t\"current\": \"%.10llx\","ZT_EOL_S + "\t\"upstream\": \"%.10llx\","ZT_EOL_S "\t\"testId\": \"%.16llx\","ZT_EOL_S "\t\"timestamp\": %llu,"ZT_EOL_S "\t\"receivedTimestamp\": %llu,"ZT_EOL_S @@ -1911,7 +1912,8 @@ void SqliteNetworkController::_circuitTestCallback(ZT_Node *node,ZT_CircuitTest "\t\"receivedFromRemoteAddress\": \"%s\""ZT_EOL_S "}", ((ftell(f) > 0) ? ",\n" : ""), - (unsigned long long)report->address, + (unsigned long long)report->current, + (unsigned long long)report->upstream, (unsigned long long)test->testId, (unsigned long long)report->timestamp, (unsigned long long)now, diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 175cedc5..80091f62 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -733,9 +733,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 diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 5d31a5d4..443ffeeb 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -993,6 +993,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); @@ -1039,13 +1040,14 @@ bool IncomingPacket::_doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,const S ZT_CircuitTestReport report; memset(&report,0,sizeof(report)); - report.address = peer->address().toInt(); + report.current = peer->address().toInt(); + report.upstream = Address(field(ZT_PACKET_IDX_PAYLOAD + 52,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH).toInt(); report.testId = at(ZT_PACKET_IDX_PAYLOAD + 8); report.timestamp = at(ZT_PACKET_IDX_PAYLOAD); report.remoteTimestamp = at(ZT_PACKET_IDX_PAYLOAD + 16); report.sourcePacketId = at(ZT_PACKET_IDX_PAYLOAD + 44); report.flags = at(ZT_PACKET_IDX_PAYLOAD + 36); - report.sourcePacketHopCount = (*this)[ZT_PACKET_IDX_PAYLOAD + 52]; + report.sourcePacketHopCount = (*this)[ZT_PACKET_IDX_PAYLOAD + 57]; // end of fixed length headers: 58 report.errorCode = at(ZT_PACKET_IDX_PAYLOAD + 34); report.vendor = (enum ZT_Vendor)((*this)[ZT_PACKET_IDX_PAYLOAD + 24]); report.protocolVersion = (*this)[ZT_PACKET_IDX_PAYLOAD + 25]; @@ -1055,10 +1057,10 @@ bool IncomingPacket::_doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,const S report.platform = (enum ZT_Platform)at(ZT_PACKET_IDX_PAYLOAD + 30); report.architecture = (enum ZT_Architecture)at(ZT_PACKET_IDX_PAYLOAD + 32); - const unsigned int receivedOnLocalAddressLen = reinterpret_cast(&(report.receivedOnLocalAddress))->deserialize(*this,ZT_PACKET_IDX_PAYLOAD + 53); - const unsigned int receivedFromRemoteAddressLen = reinterpret_cast(&(report.receivedFromRemoteAddress))->deserialize(*this,ZT_PACKET_IDX_PAYLOAD + 53 + receivedOnLocalAddressLen); + const unsigned int receivedOnLocalAddressLen = reinterpret_cast(&(report.receivedOnLocalAddress))->deserialize(*this,ZT_PACKET_IDX_PAYLOAD + 58); + const unsigned int receivedFromRemoteAddressLen = reinterpret_cast(&(report.receivedFromRemoteAddress))->deserialize(*this,ZT_PACKET_IDX_PAYLOAD + 58 + receivedOnLocalAddressLen); - unsigned int nhptr = ZT_PACKET_IDX_PAYLOAD + 53 + receivedOnLocalAddressLen + receivedFromRemoteAddressLen; + unsigned int nhptr = ZT_PACKET_IDX_PAYLOAD + 58 + receivedOnLocalAddressLen + receivedFromRemoteAddressLen; nhptr += at(nhptr) + 2; // add "additional field" length, which right now will be zero report.nextHopCount = (*this)[nhptr++]; diff --git a/node/Packet.hpp b/node/Packet.hpp index 5c7253bf..6c178e66 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -1031,6 +1031,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> -- cgit v1.2.3 From c9295a588389d5f8e017f2784a55166c46a641f4 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 9 Oct 2015 15:12:05 -0700 Subject: . --- examples/api/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/examples/api/README.md b/examples/api/README.md index 8b6d9633..50b1b65e 100644 --- a/examples/api/README.md +++ b/examples/api/README.md @@ -18,3 +18,9 @@ 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. -- cgit v1.2.3 From 7d01fab1326e3156b1327ead708457e5fefe8cdc Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 9 Oct 2015 15:18:01 -0700 Subject: Reorg fields to be in same order as FS scheme. --- controller/SqliteNetworkController.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/controller/SqliteNetworkController.cpp b/controller/SqliteNetworkController.cpp index 08bd3a15..be6145cf 100644 --- a/controller/SqliteNetworkController.cpp +++ b/controller/SqliteNetworkController.cpp @@ -1891,10 +1891,10 @@ void SqliteNetworkController::_circuitTestCallback(ZT_Node *node,ZT_CircuitTest return; fseek(f,0,SEEK_END); fprintf(f,"%s{\n" - "\t\"current\": \"%.10llx\","ZT_EOL_S - "\t\"upstream\": \"%.10llx\","ZT_EOL_S - "\t\"testId\": \"%.16llx\","ZT_EOL_S "\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 @@ -1912,10 +1912,10 @@ void SqliteNetworkController::_circuitTestCallback(ZT_Node *node,ZT_CircuitTest "\t\"receivedFromRemoteAddress\": \"%s\""ZT_EOL_S "}", ((ftell(f) > 0) ? ",\n" : ""), - (unsigned long long)report->current, - (unsigned long long)report->upstream, - (unsigned long long)test->testId, (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, -- cgit v1.2.3 From eff1fe3c61aee8029337971545da5251f470ac53 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 9 Oct 2015 16:22:34 -0700 Subject: Create files for each hop (more convenient) and fix a packet parse bug. --- controller/SqliteNetworkController.cpp | 2 +- node/IncomingPacket.cpp | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/controller/SqliteNetworkController.cpp b/controller/SqliteNetworkController.cpp index be6145cf..52b47665 100644 --- a/controller/SqliteNetworkController.cpp +++ b/controller/SqliteNetworkController.cpp @@ -1881,7 +1881,7 @@ void SqliteNetworkController::_circuitTestCallback(ZT_Node *node,ZT_CircuitTest 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"%.10llx_%.10llx",report->upstream,report->current); + Utils::snprintf(tmp,sizeof(tmp),ZT_PATH_SEPARATOR_S"%.16llx_%.10llx_%.10llx",now,report->upstream,report->current); reportSavePath.append(tmp); { diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 443ffeeb..9f53a1c5 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -1021,9 +1021,11 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt outp.append(field(remainingHopsPtr,size() - remainingHopsPtr),size() - remainingHopsPtr); for(unsigned int h=0;hsw->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); + } } } @@ -1067,7 +1069,7 @@ bool IncomingPacket::_doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,const S 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(nhptr); nhptr += 8; + report.nextHops[h].address = Address(field(nhptr,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH).toInt(); nhptr += ZT_ADDRESS_LENGTH; nhptr += reinterpret_cast(&(report.nextHops[h].physicalAddress))->deserialize(*this,nhptr); } -- cgit v1.2.3 From 70fe7dd1fdfd9834e2127bd7fc4af4f53adaff36 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 12 Oct 2015 16:40:57 -0700 Subject: cleanup --- node/Identity.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/node/Identity.hpp b/node/Identity.hpp index 18e67eb6..19bb2e1f 100644 --- a/node/Identity.hpp +++ b/node/Identity.hpp @@ -39,8 +39,6 @@ #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) - namespace ZeroTier { /** -- cgit v1.2.3 From 1b1945c63ee1ba9567b8fc5d5ed2b8946fec5f12 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 12 Oct 2015 18:25:29 -0700 Subject: Work in progress on refactoring root-topology into World and adding in-band updates. --- node/Defaults.cpp | 82 --------- node/Defaults.hpp | 74 -------- node/IncomingPacket.cpp | 6 +- node/Packet.hpp | 35 +++- node/Topology.cpp | 110 ++++-------- node/Topology.hpp | 55 +++--- node/World.hpp | 221 ++++++++++++++++++++++++ objects.mk | 1 - root-topology/Makefile | 17 -- root-topology/README.md | 18 -- root-topology/ZT_DEFAULT_ROOT_TOPOLOGY.c | 90 ---------- root-topology/ZT_DEFAULT_ROOT_TOPOLOGY.dict | 4 - root-topology/bin2c.c | 57 ------ root-topology/mktopology.cpp | 68 -------- root-topology/rootservers/7e19876aba | 4 - root-topology/rootservers/8841408a2e | 4 - root-topology/rootservers/8acf059fe3 | 4 - root-topology/rootservers/9d219039f3 | 4 - root-topology/test/README.md | 6 - root-topology/test/create-test-root-topology.sh | 31 ---- selftest.cpp | 1 - 21 files changed, 317 insertions(+), 575 deletions(-) delete mode 100644 node/Defaults.cpp delete mode 100644 node/Defaults.hpp create mode 100644 node/World.hpp delete mode 100644 root-topology/Makefile delete mode 100644 root-topology/README.md delete mode 100644 root-topology/ZT_DEFAULT_ROOT_TOPOLOGY.c delete mode 100644 root-topology/ZT_DEFAULT_ROOT_TOPOLOGY.dict delete mode 100644 root-topology/bin2c.c delete mode 100644 root-topology/mktopology.cpp delete mode 100644 root-topology/rootservers/7e19876aba delete mode 100644 root-topology/rootservers/8841408a2e delete mode 100644 root-topology/rootservers/8acf059fe3 delete mode 100644 root-topology/rootservers/9d219039f3 delete mode 100644 root-topology/test/README.md delete mode 100755 root-topology/test/create-test-root-topology.sh 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 . - * - * -- - * - * 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 -#include -#include - -#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 -#include -#include -#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/Defaults.hpp b/node/Defaults.hpp deleted file mode 100644 index c1df919b..00000000 --- a/node/Defaults.hpp +++ /dev/null @@ -1,74 +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 . - * - * -- - * - * 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_DEFAULTS_HPP -#define ZT_DEFAULTS_HPP - -#include -#include -#include -#include - -#include "Constants.hpp" -#include "Identity.hpp" -#include "InetAddress.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 -{ -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; - -} // namespace ZeroTier - -#endif diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 9f53a1c5..9fcc2e49 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -835,7 +835,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha 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(ptr); ptr += 2; @@ -846,14 +846,14 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha switch(addrType) { case 4: { InetAddress a(field(ptr,4),4,at(ptr + 4)); - if ( ((flags & (0x01 | 0x02)) == 0) && (Path::isAddressValidForPath(a)) ) { + if ( ((flags & 0x01) == 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()); } } break; case 6: { InetAddress a(field(ptr,16),16,at(ptr + 16)); - if ( ((flags & (0x01 | 0x02)) == 0) && (Path::isAddressValidForPath(a)) ) { + if ( ((flags & 0x01) == 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()); } diff --git a/node/Packet.hpp b/node/Packet.hpp index 6c178e66..958d0f3e 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -564,6 +564,8 @@ public: * <[2] software revision (of responder)> * <[1] destination address type (for this OK, not copied from HELLO)> * [<[...] destination address>] + * <[8] 64-bit world ID of current world> + * <[8] 64-bit timestamp of current world> * * ERROR has no payload. */ @@ -911,7 +913,7 @@ 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) * @@ -1094,7 +1096,36 @@ public: * * ERROR has no payload. */ - VERB_REQUEST_PROOF_OF_WORK = 19 + VERB_REQUEST_PROOF_OF_WORK = 19, + + /** + * Generic binary object access: + * <[8] 64-bit request ID> + * <[4] 32-bit index in blob to retrieve> + * <[2] 16-bit max length of block to retrieve> + * <[2] 16-bit length of blob identifier> + * <[...] blob identifier> + * + * This is used as a generic remote object retrieval mechanism. It returns + * OK if the object is accessible, INVALID_REQUEST if the index is beyond + * the size of the blob or another element is invalid, and OBJ_NOT_FOUND + * if no blob with the given identifier is available. + * + * Blob identifiers follow a de facto path-like schema, with the following + * names reserved: + * world - Current world definition (see World.hpp) + * updates.d/ - Software updates (not used yet, but reserved) + * + * OK payload: + * <[8] 64-bit request ID> + * <[4] 32-bit total length of blob> + * <[4] 32-bit index of this data in blob> + * <[...] data> + * + * ERROR payload: + * <[8] 64-bit request ID> + */ + VERB_GET_OBJECT = 20 }; /** diff --git a/node/Topology.cpp b/node/Topology.cpp index 908acbc8..5aedae86 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -28,17 +28,37 @@ #include "Constants.hpp" #include "Topology.hpp" #include "RuntimeEnvironment.hpp" -#include "Defaults.hpp" #include "Dictionary.hpp" #include "Node.hpp" #include "Buffer.hpp" namespace ZeroTier { +// Default World +#define ZT_DEFAULT_WORLD_LENGTH 1 +static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = { 0 }; + Topology::Topology(const RuntimeEnvironment *renv) : RR(renv), _amRoot(false) { + try { + std::string dsWorld(RR->node->dataStoreGet("world")); + Buffer dswtmp(dsWorld.data(),dsWorld.length()); + _world.deserialize(dswtmp,0); + } catch ( ... ) { + _world = World(); // set to null if cached world is invalid + } + { + World defaultWorld; + Buffer wtmp(ZT_DEFAULT_WORLD,ZT_DEFAULT_WORLD_LENGTH); + defaultWorld.deserialize(wtmp,0); // throws on error, which would indicate a bad static variable up top + if (_world.verifyUpdate(defaultWorld)) { + _world = defaultWorld; + RR->node->dataStorePut("world",ZT_DEFAULT_WORLD,ZT_DEFAULT_WORLD_LENGTH,false); + } + } + std::string alls(RR->node->dataStoreGet("peers.save")); const uint8_t *all = reinterpret_cast(alls.data()); RR->node->dataStoreDelete("peers.save"); @@ -76,6 +96,20 @@ Topology::Topology(const RuntimeEnvironment *renv) : } clean(RR->node->now()); + + for(std::vector::const_iterator r(_world.roots().begin());r!=_world.roots().end();++r) { + if (r->identity == RR->identity) + _amRoot = true; + _rootAddresses.push_back(r->identity.address()); + SharedPtr *rp = _peers.get(r->identity.address()); + if (rp) { + _rootPeers.push_back(*rp); + } else if (r->identity.address() != RR->identity.address()) { + SharedPtr newrp(new Peer(RR->identity,r->identity)); + _peers.set(r->identity.address(),newrp); + _rootPeers.push_back(newrp); + } + } } Topology::~Topology() @@ -103,55 +137,6 @@ Topology::~Topology() RR->node->dataStorePut("peers.save",all,true); } -void Topology::setRootServers(const std::map< Identity,std::vector > &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 >::const_iterator i(sn.begin());i!=sn.end();++i) { - if (i->first != RR->identity) { // do not add self as a peer - SharedPtr &p = _peers[i->first.address()]; - if (!p) - p = SharedPtr(new Peer(RR->identity,i->first)); - for(std::vector::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()); - } - - std::sort(_rootAddresses.begin(),_rootAddresses.end()); - - _amRoot = (_roots.find(RR->identity) != _roots.end()); -} - -void Topology::setRootServers(const Dictionary &sn) -{ - std::map< Identity,std::vector > 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 &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()); - } - } - } - this->setRootServers(m); -} - SharedPtr Topology::addPeer(const SharedPtr &peer) { if (peer->address() == RR->identity.address()) { @@ -298,13 +283,6 @@ keep_searching_for_roots: return bestRoot; } -bool Topology::isRoot(const Identity &id) const - throw() -{ - Mutex::Lock _l(_lock); - return (_roots.count(id) != 0); -} - void Topology::clean(uint64_t now) { Mutex::Lock _l(_lock); @@ -320,24 +298,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]; diff --git a/node/Topology.hpp b/node/Topology.hpp index 4df545e1..ed8f3d86 100644 --- a/node/Topology.hpp +++ b/node/Topology.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 { @@ -59,21 +59,6 @@ public: Topology(const RuntimeEnvironment *renv); ~Topology(); - /** - * @param sn Root server identities and addresses - */ - void setRootServers(const std::map< Identity,std::vector > &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 * @@ -128,10 +113,20 @@ 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); + if (std::find(_rootAddresses.begin(),_rootAddresses.end(),id.address()) != _rootAddresses.end()) { + // Double check full identity for security reasons + for(std::vector::const_iterator r(_world.roots().begin());r!=_world.roots().end();++r) { + if (id == r->identity) + return true; + } + } + return false; + } /** * @return Vector of root server addresses @@ -142,6 +137,15 @@ public: return _rootAddresses; } + /** + * @return Current World (copy) + */ + inline World world() const + { + Mutex::Lock _l(_lock); + return _world; + } + /** * Clean and flush database */ @@ -180,28 +184,19 @@ public: return _peers.entries(); } - /** - * Validate a root topology dictionary against the identities specified in Defaults - * - * @param rt Root topology dictionary - * @return True if dictionary signature is valid - */ - static bool authenticateRootTopology(const Dictionary &rt); - private: Identity _getIdentity(const Address &zta); void _saveIdentity(const Identity &id); const RuntimeEnvironment *RR; + World _world; Hashtable< Address,SharedPtr > _peers; - std::map< Identity,std::vector > _roots; std::vector< Address > _rootAddresses; std::vector< SharedPtr > _rootPeers; + bool _amRoot; Mutex _lock; - - bool _amRoot; }; } // namespace ZeroTier diff --git a/node/World.hpp b/node/World.hpp new file mode 100644 index 00000000..0d26021f --- /dev/null +++ b/node/World.hpp @@ -0,0 +1,221 @@ +/* + * 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 . + * + * -- + * + * 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 +#include + +#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 + 64) + +/** + * 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 -- its approximate distance from the sun in kilometers + * + * 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's advisable to create a new World for network regions spaced more than + * 2-3 light seconds, since RTT times in excess of 5s are problematic for some + * protocols. Earth could therefore include its low and high orbits, the Moon, + * and nearby Lagrange points. + */ +#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) + * + * A world consists of a set of root servers and a signature scheme enabling + * it to be updated going forward. It defines a single ZeroTier VL1 network + * area within which any device can reach any other. + */ +class World +{ +public: + struct Root + { + Identity identity; + std::vector 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 &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; } + + /** + * Verify a world update + * + * 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 + * @return True if update is newer than current and is properly signed + */ + inline bool verifyUpdate(const World &update) + { + if (_id == ZT_WORLD_ID_NULL) + return true; + if ((update._id != _id)||(update._ts <= _ts)) + return false; + Buffer tmp; + update.serialize(tmp); + return C25519::verify(_updateSigningKey,tmp.data(),tmp.size(),update._signature); + } + + /** + * @return True if this World is non-empty + */ + inline operator bool() const throw() { return (_id != ZT_WORLD_ID_NULL); } + + template + inline void serialize(Buffer &b) const + { + 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); + b.append(_signature.data,ZT_C25519_SIGNATURE_LEN); + b.append((uint8_t)_roots.size()); + for(std::vector::const_iterator r(_roots.begin());r!=_roots.end();++r) { + r->identity.serialize(b); + b.append((uint8_t)r->stableEndpoints.size()); + for(std::vector::const_iterator ep(r->stableEndpoints.begin());ep!=r->stableEndpoints.end();++ep) + ep->serialize(b); + } + } + + template + inline unsigned int deserialize(const Buffer &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(p); p += 8; + _ts = b.template at(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 ZT_WORLD_MAX_STABLE_ENDPOINTS_PER_ROOT) + throw std::invalid_argument("too many stable endpoints in World/Root"); + for(unsigned int kk=0;kk _roots; +}; + +} // namespace ZeroTier + +#endif diff --git a/objects.mk b/objects.mk index 0986ef0d..64e5cfa7 100644 --- a/objects.mk +++ b/objects.mk @@ -4,7 +4,6 @@ OBJS=\ ext/http-parser/http_parser.o \ node/C25519.o \ node/CertificateOfMembership.o \ - node/Defaults.o \ node/Dictionary.o \ node/Identity.o \ node/IncomingPacket.o \ 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 /* uintXX_t */ -#include /* PRIuXX macros */ -#include - -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 -#include -#include - -#include -#include -#include - -#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 rootserverDictionaries(OSUtils::listDirectory("rootservers")); - for(std::vector::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 4ba76c0b..9c357dc4 100644 --- a/selftest.cpp +++ b/selftest.cpp @@ -50,7 +50,6 @@ #include "node/C25519.hpp" #include "node/Poly1305.hpp" #include "node/CertificateOfMembership.hpp" -#include "node/Defaults.hpp" #include "node/Node.hpp" #include "node/IncomingPacket.hpp" -- cgit v1.2.3 From cae58f43f1b18017b90499811772d107ea2f65b9 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 13 Oct 2015 08:49:36 -0700 Subject: More World stuff, and mkworld. --- include/ZeroTierOne.h | 4 +- make-mac.mk | 6 +- mkworld.cpp | 153 ++++++++++++++++++++++++++++++++++++++++++++++++ node/IncomingPacket.cpp | 1 - node/Node.cpp | 24 +------- node/Node.hpp | 3 +- node/Packet.hpp | 6 +- node/Topology.cpp | 78 +++++++++++++++--------- node/Topology.hpp | 22 ++++++- node/World.hpp | 60 ++++++++++++------- one.cpp | 16 +---- service/OneService.cpp | 9 +-- service/OneService.hpp | 4 +- 13 files changed, 281 insertions(+), 105 deletions(-) create mode 100644 mkworld.cpp diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 80091f62..f69ab54c 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -1023,7 +1023,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( @@ -1035,8 +1034,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 diff --git a/make-mac.mk b/make-mac.mk index 6daa6aa0..9fb613d8 100644 --- a/make-mac.mk +++ b/make-mac.mk @@ -79,6 +79,10 @@ selftest: $(OBJS) selftest.o $(CXX) $(CXXFLAGS) -o zerotier-selftest selftest.o $(OBJS) $(LIBS) $(STRIP) zerotier-selftest +mkworld: $(OBJS) + rm -f mkworld + $(CXX) $(CXXFLAGS) -o mkworld mkworld.cpp $(OBJS) $(LIBS) + # Requires Packages: http://s.sudre.free.fr/Software/Packages/about.html mac-dist-pkg: FORCE packagesbuild "ext/installfiles/mac/ZeroTier One.pkgproj" @@ -93,7 +97,7 @@ 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 # For those building from source -- installs signed binary tap driver in system ZT home install-mac-tap: FORCE diff --git a/mkworld.cpp b/mkworld.cpp new file mode 100644 index 00000000..2b41d735 --- /dev/null +++ b/mkworld.cpp @@ -0,0 +1,153 @@ +/* + * 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 . + * + * -- + * + * 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 +#include +#include +#include + +#include +#include +#include + +#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 &roots,const C25519::Pair &signWith) + { + WorldMaker w; + w._id = id; + w._ts = ts; + w._updateSigningKey = sk; + w._roots = roots; + + Buffer 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, current.c25519"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 roots; + + // old US-SFO + roots.push_back(World::Root()); + roots.back().identity = Identity("7e19876aba:0:2a6e2b2318930f60eb097f70d0f4b028b2cd6d3d0c63c014b9039ff35390e41181f216fb2e6fa8d95c1ee9667156411905c3dccfea78d8c6dfafba688170b3fa"); + roots.back().stableEndpoints.push_back(InetAddress("198.199.97.220/9993")); + std::sort(roots.back().stableEndpoints.begin(),roots.back().stableEndpoints.end()); + + // old EU-PARIS + roots.push_back(World::Root()); + roots.back().identity = Identity("8841408a2e:0:bb1d31f2c323e264e9e64172c1a74f77899555ed10751cd56e86405cde118d02dffe555d462ccf6a85b5631c12350c8d5dc409ba10b9025d0f445cf449d92b1c"); + roots.back().stableEndpoints.push_back(InetAddress("107.191.46.210/9993")); + std::sort(roots.back().stableEndpoints.begin(),roots.back().stableEndpoints.end()); + + // old US-NYC + roots.push_back(World::Root()); + roots.back().identity = Identity("8acf059fe3:0:482f6ee5dfe902319b419de5bdc765209c0ecda38c4d6e4fcf0d33658398b4527dcd22f93112fb9befd02fd78bf7261b333fc105d192a623ca9e50fc60b374a5"); + roots.back().stableEndpoints.push_back(InetAddress("162.243.77.111/9993")); + std::sort(roots.back().stableEndpoints.begin(),roots.back().stableEndpoints.end()); + + // old AP-SNG + roots.push_back(World::Root()); + roots.back().identity = Identity("9d219039f3:0:01f0922a98e3b34ebcbff333269dc265d7a020aab69d72be4d4acc9c8c9294785771256cd1d942a90d1bd1d2dca3ea84ef7d85afe6611fb43ff0b74126d90a6e"); + roots.back().stableEndpoints.push_back(InetAddress("128.199.197.217/9993")); + std::sort(roots.back().stableEndpoints.begin(),roots.back().stableEndpoints.end()); + + std::sort(roots.begin(),roots.end()); + + const uint64_t id = ZT_WORLD_ID_EARTH; + const uint64_t ts = OSUtils::now(); + + // END WORLD SETUP --------------------------------------------------------- + + 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 outtmp; + nw.serialize(outtmp,false); + fwrite(outtmp.data(),outtmp.size(),1,stdout); + fflush(stdout); + + fprintf(stderr,"INFO: wrote %u bytes to stdout"ZT_EOL_S,outtmp.size()); + + return 0; +} diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 9fcc2e49..39abe720 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" diff --git a/node/Node.cpp b/node/Node.cpp index 1eb21914..7496b045 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -46,7 +46,6 @@ #include "Address.hpp" #include "Identity.hpp" #include "SelfAwareness.hpp" -#include "Defaults.hpp" const struct sockaddr_storage ZT_SOCKADDR_NULL = {0}; @@ -64,8 +63,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), @@ -125,21 +123,6 @@ 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); } @@ -609,12 +592,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(new ZeroTier::Node(now,uptr,dataStoreGetFunction,dataStorePutFunction,wirePacketSendFunction,virtualNetworkFrameFunction,virtualNetworkConfigFunction,eventCallback,overrideRootTopology)); + *node = reinterpret_cast(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; diff --git a/node/Node.hpp b/node/Node.hpp index 0ae176c0..c7038ed4 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(); diff --git a/node/Packet.hpp b/node/Packet.hpp index 958d0f3e..939d84a5 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -540,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. @@ -564,8 +566,8 @@ public: * <[2] software revision (of responder)> * <[1] destination address type (for this OK, not copied from HELLO)> * [<[...] destination address>] - * <[8] 64-bit world ID of current world> - * <[8] 64-bit timestamp of current world> + * <[8] 64-bit world ID of current world (of responder)> + * <[8] 64-bit timestamp of current world (of responder)> * * ERROR has no payload. */ diff --git a/node/Topology.cpp b/node/Topology.cpp index 5aedae86..0cf4cfe8 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -42,23 +42,6 @@ Topology::Topology(const RuntimeEnvironment *renv) : RR(renv), _amRoot(false) { - try { - std::string dsWorld(RR->node->dataStoreGet("world")); - Buffer dswtmp(dsWorld.data(),dsWorld.length()); - _world.deserialize(dswtmp,0); - } catch ( ... ) { - _world = World(); // set to null if cached world is invalid - } - { - World defaultWorld; - Buffer wtmp(ZT_DEFAULT_WORLD,ZT_DEFAULT_WORLD_LENGTH); - defaultWorld.deserialize(wtmp,0); // throws on error, which would indicate a bad static variable up top - if (_world.verifyUpdate(defaultWorld)) { - _world = defaultWorld; - RR->node->dataStorePut("world",ZT_DEFAULT_WORLD,ZT_DEFAULT_WORLD_LENGTH,false); - } - } - std::string alls(RR->node->dataStoreGet("peers.save")); const uint8_t *all = reinterpret_cast(alls.data()); RR->node->dataStoreDelete("peers.save"); @@ -97,19 +80,24 @@ Topology::Topology(const RuntimeEnvironment *renv) : clean(RR->node->now()); - for(std::vector::const_iterator r(_world.roots().begin());r!=_world.roots().end();++r) { - if (r->identity == RR->identity) - _amRoot = true; - _rootAddresses.push_back(r->identity.address()); - SharedPtr *rp = _peers.get(r->identity.address()); - if (rp) { - _rootPeers.push_back(*rp); - } else if (r->identity.address() != RR->identity.address()) { - SharedPtr newrp(new Peer(RR->identity,r->identity)); - _peers.set(r->identity.address(),newrp); - _rootPeers.push_back(newrp); - } + std::string dsWorld(RR->node->dataStoreGet("world")); + World cachedWorld; + try { + Buffer dswtmp(dsWorld.data(),dsWorld.length()); + cachedWorld.deserialize(dswtmp,0); + } catch ( ... ) { + cachedWorld = World(); // clear if cached world is invalid } + World defaultWorld; + { + Buffer wtmp(ZT_DEFAULT_WORLD,ZT_DEFAULT_WORLD_LENGTH); + defaultWorld.deserialize(wtmp,0); // throws on error, which would indicate a bad static variable up top + } + if (cachedWorld.shouldBeReplacedBy(defaultWorld,false)) { + _setWorld(defaultWorld); + if (dsWorld.length() > 0) + RR->node->dataStoreDelete("world"); + } else _setWorld(cachedWorld); } Topology::~Topology() @@ -283,6 +271,16 @@ keep_searching_for_roots: return bestRoot; } +bool Topology::worldUpdateIfValid(const World &newWorld) +{ + Mutex::Lock _l(_lock); + if (_world.shouldBeReplacedBy(newWorld,true)) { + _setWorld(newWorld); + return true; + } + return false; +} + void Topology::clean(uint64_t now) { Mutex::Lock _l(_lock); @@ -320,4 +318,26 @@ void Topology::_saveIdentity(const Identity &id) } } +void Topology::_setWorld(const World &newWorld) +{ + // assumed _lock is locked (or in constructor) + _world = newWorld; + _amRoot = false; + _rootAddresses.clear(); + _rootPeers.clear(); + for(std::vector::const_iterator r(_world.roots().begin());r!=_world.roots().end();++r) { + if (r->identity == RR->identity) + _amRoot = true; + _rootAddresses.push_back(r->identity.address()); + SharedPtr *rp = _peers.get(r->identity.address()); + if (rp) { + _rootPeers.push_back(*rp); + } else if (r->identity.address() != RR->identity.address()) { + SharedPtr newrp(new Peer(RR->identity,r->identity)); + _peers.set(r->identity.address(),newrp); + _rootPeers.push_back(newrp); + } + } +} + } // namespace ZeroTier diff --git a/node/Topology.hpp b/node/Topology.hpp index ed8f3d86..3abc27e4 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -31,10 +31,10 @@ #include #include -#include #include #include #include +#include #include "Constants.hpp" @@ -146,6 +146,23 @@ public: return _world; } + /** + * @return Pair containing world ID and world timestamp (faster than world().id() etc.) + */ + inline std::pair worldIdentification() const + { + Mutex::Lock _l(_lock); + return std::pair(_world.id(),_world.timestamp()); + } + + /** + * 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 */ @@ -176,7 +193,7 @@ public: } /** - * @return All currently active peers by address + * @return All currently active peers by address (unsorted) */ inline std::vector< std::pair< Address,SharedPtr > > allPeers() const { @@ -187,6 +204,7 @@ public: private: Identity _getIdentity(const Address &zta); void _saveIdentity(const Identity &id); + void _setWorld(const World &newWorld); const RuntimeEnvironment *RR; diff --git a/node/World.hpp b/node/World.hpp index 0d26021f..7ccd2c53 100644 --- a/node/World.hpp +++ b/node/World.hpp @@ -55,7 +55,7 @@ /** * 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 + 64) +#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 @@ -68,15 +68,11 @@ #define ZT_WORLD_ID_TESTNET 1 /** - * World ID for Earth -- its approximate distance from the sun in kilometers + * 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's advisable to create a new World for network regions spaced more than - * 2-3 light seconds, since RTT times in excess of 5s are problematic for some - * protocols. Earth could therefore include its low and high orbits, the Moon, - * and nearby Lagrange points. + * 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 @@ -90,9 +86,24 @@ namespace ZeroTier { /** * A world definition (formerly known as a root topology) * - * A world consists of a set of root servers and a signature scheme enabling - * it to be updated going forward. It defines a single ZeroTier VL1 network - * area within which any device can reach any other. + * 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 { @@ -130,24 +141,28 @@ public: inline uint64_t timestamp() const throw() { return _ts; } /** - * Verify a world update + * 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 verifyUpdate(const World &update) + inline bool shouldBeReplacedBy(const World &update,bool fullSignatureCheck) { if (_id == ZT_WORLD_ID_NULL) return true; - if ((update._id != _id)||(update._ts <= _ts)) - return false; - Buffer tmp; - update.serialize(tmp); - return C25519::verify(_updateSigningKey,tmp.data(),tmp.size(),update._signature); + if ((_id == update._id)&&(_ts < update._ts)) { + if (fullSignatureCheck) { + Buffer tmp; + update.serialize(tmp,true); + return C25519::verify(_updateSigningKey,tmp.data(),tmp.size(),update._signature); + } else return true; + } + return false; } /** @@ -156,13 +171,16 @@ public: inline operator bool() const throw() { return (_id != ZT_WORLD_ID_NULL); } template - inline void serialize(Buffer &b) const + inline void serialize(Buffer &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); - b.append(_signature.data,ZT_C25519_SIGNATURE_LEN); + if (!forSign) + b.append(_signature.data,ZT_C25519_SIGNATURE_LEN); b.append((uint8_t)_roots.size()); for(std::vector::const_iterator r(_roots.begin());r!=_roots.end();++r) { r->identity.serialize(b); @@ -170,6 +188,8 @@ public: for(std::vector::const_iterator ep(r->stableEndpoints.begin());ep!=r->stableEndpoints.end();++ep) ep->serialize(b); } + if (forSign) + b.append((uint64_t)0xf7f7f7f7f7f7f7f7ULL); } template diff --git a/one.cpp b/one.cpp index a4d5190c..c8661fda 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 for UDP and TCP/HTTP (default: 9993, 0 for random)"ZT_EOL_S); - //fprintf(out," -T - 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); @@ -974,7 +973,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 +999,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; @@ -1169,7 +1155,7 @@ int main(int argc,char **argv) try { for(;;) { - zt1Service = OneService::newInstance(homeDir.c_str(),port,(overrideRootTopology.length() > 0) ? overrideRootTopology.c_str() : (const char *)0); + 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: diff --git a/service/OneService.cpp b/service/OneService.cpp index 071a2cbc..6b28c41e 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -418,14 +418,13 @@ struct TcpConnection class OneServiceImpl : public OneService { public: - OneServiceImpl(const char *hp,unsigned int port,const char *overrideRootTopology) : + OneServiceImpl(const char *hp,unsigned int port) : _homePath((hp) ? hp : "."), _tcpFallbackResolver(ZT_TCP_FALLBACK_RELAY), #ifdef ZT_ENABLE_NETWORK_CONTROLLER _controller((SqliteNetworkController *)0), #endif _phy(this,false,true), - _overrideRootTopology((overrideRootTopology) ? overrideRootTopology : ""), _node((Node *)0), _controlPlane((ControlPlane *)0), _lastDirectReceiveFromGlobal(0), @@ -550,8 +549,7 @@ 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()); @@ -1329,7 +1327,6 @@ private: SqliteNetworkController *_controller; #endif Phy _phy; - std::string _overrideRootTopology; Node *_node; InetAddress _v4LocalAddress,_v6LocalAddress; PhySocket *_v4UdpSocket; @@ -1526,7 +1523,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..2f76ebaa 100644 --- a/service/OneService.hpp +++ b/service/OneService.hpp @@ -95,12 +95,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(); -- cgit v1.2.3 From 05677f57e2e6bed58467198f4e65b68a236b00c2 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 13 Oct 2015 08:55:21 -0700 Subject: Add C output to mkworld. --- .gitignore | 1 + mkworld.cpp | 17 +++++++++++++++++ node/World.hpp | 2 +- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index b5d71690..1cb16da5 100755 --- a/.gitignore +++ b/.gitignore @@ -31,6 +31,7 @@ Thumbs.db /ZeroTierOneInstaller-* /examples/docker/zerotier-one /examples/docker/test-*.env +/mkworld # Miscellaneous file types that we don't want to check in *.log diff --git a/mkworld.cpp b/mkworld.cpp index 2b41d735..baf693fc 100644 --- a/mkworld.cpp +++ b/mkworld.cpp @@ -144,10 +144,27 @@ int main(int argc,char **argv) Buffer 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; + } fwrite(outtmp.data(),outtmp.size(),1,stdout); fflush(stdout); fprintf(stderr,"INFO: wrote %u bytes to stdout"ZT_EOL_S,outtmp.size()); + fprintf(stderr,ZT_EOL_S); + fprintf(stderr,"#define ZT_DEFAULT_WORLD_LENGTH %u"ZT_EOL_S,outtmp.size()); + fprintf(stderr,"static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {"); + for(unsigned int i=0;i 0) + fprintf(stderr,","); + fprintf(stderr,"0x%.2x",(unsigned int)d[i]); + } + fprintf(stderr,"};"ZT_EOL_S); + return 0; } diff --git a/node/World.hpp b/node/World.hpp index 7ccd2c53..c6d20d84 100644 --- a/node/World.hpp +++ b/node/World.hpp @@ -225,7 +225,7 @@ public: return (p - startAt); } - inline bool operator==(const World &w) const throw() { return ((_id == w._id)&&(_ts == w._ts)&&(_roots == w._roots)); } + 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: -- cgit v1.2.3 From 5d2f523e81a56a33405d2b98ccef9d384e269f34 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 13 Oct 2015 12:10:44 -0700 Subject: World stuff... --- .gitignore | 3 +- include/ZeroTierOne.h | 5 -- make-mac.mk | 4 -- mkworld.cpp | 170 ----------------------------------------------- node/IncomingPacket.cpp | 34 ++++++++-- node/Node.cpp | 39 ++++++----- node/Packet.hpp | 35 +--------- node/Peer.cpp | 71 +++----------------- node/Peer.hpp | 25 ++----- node/RemotePath.hpp | 26 ++------ node/Topology.cpp | 11 ++- node/Topology.hpp | 15 +++-- service/ControlPlane.cpp | 2 - world/2015-10-13.bin | Bin 0 -> 494 bytes world/2015-10-13.out | 6 ++ world/mkworld.cpp | 170 +++++++++++++++++++++++++++++++++++++++++++++++ 16 files changed, 271 insertions(+), 345 deletions(-) delete mode 100644 mkworld.cpp create mode 100644 world/2015-10-13.bin create mode 100644 world/2015-10-13.out create mode 100644 world/mkworld.cpp diff --git a/.gitignore b/.gitignore index 1cb16da5..2dbec1e5 100755 --- a/.gitignore +++ b/.gitignore @@ -31,7 +31,8 @@ Thumbs.db /ZeroTierOneInstaller-* /examples/docker/zerotier-one /examples/docker/test-*.env -/mkworld +/world/mkworld +/world/*.c25519 # Miscellaneous file types that we don't want to check in *.log diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index f69ab54c..38db3222 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -582,11 +582,6 @@ typedef struct */ uint64_t lastReceive; - /** - * Is path fixed? (i.e. not learned, static) - */ - int fixed; - /** * Is path active? */ diff --git a/make-mac.mk b/make-mac.mk index 9fb613d8..174216fb 100644 --- a/make-mac.mk +++ b/make-mac.mk @@ -79,10 +79,6 @@ selftest: $(OBJS) selftest.o $(CXX) $(CXXFLAGS) -o zerotier-selftest selftest.o $(OBJS) $(LIBS) $(STRIP) zerotier-selftest -mkworld: $(OBJS) - rm -f mkworld - $(CXX) $(CXXFLAGS) -o mkworld mkworld.cpp $(OBJS) $(LIBS) - # Requires Packages: http://s.sudre.free.fr/Software/Packages/about.html mac-dist-pkg: FORCE packagesbuild "ext/installfiles/mac/ZeroTier One.pkgproj" diff --git a/mkworld.cpp b/mkworld.cpp deleted file mode 100644 index baf693fc..00000000 --- a/mkworld.cpp +++ /dev/null @@ -1,170 +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 . - * - * -- - * - * 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 -#include -#include -#include - -#include -#include -#include - -#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 &roots,const C25519::Pair &signWith) - { - WorldMaker w; - w._id = id; - w._ts = ts; - w._updateSigningKey = sk; - w._roots = roots; - - Buffer 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, current.c25519"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 roots; - - // old US-SFO - roots.push_back(World::Root()); - roots.back().identity = Identity("7e19876aba:0:2a6e2b2318930f60eb097f70d0f4b028b2cd6d3d0c63c014b9039ff35390e41181f216fb2e6fa8d95c1ee9667156411905c3dccfea78d8c6dfafba688170b3fa"); - roots.back().stableEndpoints.push_back(InetAddress("198.199.97.220/9993")); - std::sort(roots.back().stableEndpoints.begin(),roots.back().stableEndpoints.end()); - - // old EU-PARIS - roots.push_back(World::Root()); - roots.back().identity = Identity("8841408a2e:0:bb1d31f2c323e264e9e64172c1a74f77899555ed10751cd56e86405cde118d02dffe555d462ccf6a85b5631c12350c8d5dc409ba10b9025d0f445cf449d92b1c"); - roots.back().stableEndpoints.push_back(InetAddress("107.191.46.210/9993")); - std::sort(roots.back().stableEndpoints.begin(),roots.back().stableEndpoints.end()); - - // old US-NYC - roots.push_back(World::Root()); - roots.back().identity = Identity("8acf059fe3:0:482f6ee5dfe902319b419de5bdc765209c0ecda38c4d6e4fcf0d33658398b4527dcd22f93112fb9befd02fd78bf7261b333fc105d192a623ca9e50fc60b374a5"); - roots.back().stableEndpoints.push_back(InetAddress("162.243.77.111/9993")); - std::sort(roots.back().stableEndpoints.begin(),roots.back().stableEndpoints.end()); - - // old AP-SNG - roots.push_back(World::Root()); - roots.back().identity = Identity("9d219039f3:0:01f0922a98e3b34ebcbff333269dc265d7a020aab69d72be4d4acc9c8c9294785771256cd1d942a90d1bd1d2dca3ea84ef7d85afe6611fb43ff0b74126d90a6e"); - roots.back().stableEndpoints.push_back(InetAddress("128.199.197.217/9993")); - std::sort(roots.back().stableEndpoints.begin(),roots.back().stableEndpoints.end()); - - std::sort(roots.begin(),roots.end()); - - const uint64_t id = ZT_WORLD_ID_EARTH; - const uint64_t ts = OSUtils::now(); - - // END WORLD SETUP --------------------------------------------------------- - - 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 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; - } - fwrite(outtmp.data(),outtmp.size(),1,stdout); - fflush(stdout); - - fprintf(stderr,"INFO: wrote %u bytes to stdout"ZT_EOL_S,outtmp.size()); - - fprintf(stderr,ZT_EOL_S); - fprintf(stderr,"#define ZT_DEFAULT_WORLD_LENGTH %u"ZT_EOL_S,outtmp.size()); - fprintf(stderr,"static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {"); - for(unsigned int i=0;i 0) - fprintf(stderr,","); - fprintf(stderr,"0x%.2x",(unsigned int)d[i]); - } - fprintf(stderr,"};"ZT_EOL_S); - - return 0; -} diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 39abe720..3c6268ed 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -42,6 +42,7 @@ #include "SelfAwareness.hpp" #include "Salsa20.hpp" #include "SHA512.hpp" +#include "World.hpp" namespace ZeroTier { @@ -199,10 +200,18 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) const uint64_t timestamp = at(ZT_PROTO_VERB_HELLO_IDX_TIMESTAMP); Identity id; - const unsigned int destAddrPtr = ZT_PROTO_VERB_HELLO_IDX_IDENTITY + id.deserialize(*this,ZT_PROTO_VERB_HELLO_IDX_IDENTITY); InetAddress destAddr; - if (destAddrPtr < size()) // ZeroTier One < 1.0.3 did not include this field - destAddr.deserialize(*this,destAddrPtr); + 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 += destAddr.deserialize(*this,ptr); + if ((ptr + 16) <= size()) { // older versions also did not include World IDs or timestamps + worldId = at(ptr); ptr += 8; + worldTimestamp = at(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()); @@ -286,8 +295,23 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) outp.append((unsigned char)ZEROTIER_ONE_VERSION_MINOR); outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION); _remoteAddress.serialize(outp); - outp.armor(peer->key(),true); - RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); + + if ((worldId != ZT_WORLD_ID_NULL)&&(worldId == RR->topology->worldId())) { + if (RR->topology->worldTimestamp() > worldTimestamp) { + 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(sizeAt,(uint16_t)(outp.size() - sizeAt)); + } else { + outp.append((uint16_t)0); // no world update needed + } + + outp.armor(peer->key(),true); + RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); + } else { + TRACE("dropped HELLO from %s(%s): world ID mismatch: peer is %llu and we are %llu",source().toString().c_str(),_remoteAddress.toString().c_str(),worldId,RR->topology->worldId()); + } } catch ( ... ) { TRACE("dropped HELLO from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); } diff --git a/node/Node.cpp b/node/Node.cpp index 7496b045..5468f102 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -177,37 +177,47 @@ 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 &p) { - bool isRelay = false; - for(std::vector< std::pair >::const_iterator r(_relays.begin());r!=_relays.end();++r) { - if (r->first == p->address()) { - isRelay = true; + bool upstream = false; + InetAddress stableEndpoint; + for(std::vector::const_iterator r(_world.roots().begin());r!=_world.roots().end();++r) { + if (r->identity.address() == p->address()) { + if (r->stableEndpoints.size() > 0) + stableEndpoint = r->stableEndpoints[(unsigned long)RR->node->prng() % r->stableEndpoints.size()]; + upstream = true; 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) { + for(std::vector< std::pair >::const_iterator r(_relays.begin());r!=_relays.end();++r) { + if (r->first == p->address()) { + stableEndpoint = r->second; + upstream = true; + break; + } + } } + + if ((!p->doPingAndKeepalive(RR,_now))&&(stableEndpoint)) + p->attemptToContactAt(RR,InetAddress(),stableEndpoint,_now); + + if (upstream) + lastReceiveFromUpstream = std::max(p->lastReceive(),lastReceiveFromUpstream); } private: const RuntimeEnvironment *RR; uint64_t _now; const std::vector< std::pair > &_relays; - std::vector

_rootAddresses; + World _world; }; ZT_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline) @@ -376,7 +386,6 @@ ZT_PeerList *Node::peers() const 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; diff --git a/node/Packet.hpp b/node/Packet.hpp index 939d84a5..810f5d67 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -566,8 +566,8 @@ public: * <[2] software revision (of responder)> * <[1] destination address type (for this OK, not copied from HELLO)> * [<[...] destination address>] - * <[8] 64-bit world ID of current world (of responder)> - * <[8] 64-bit timestamp of current world (of responder)> + * <[2] 16-bit length of world update or 0 if none> + * [[...] world update] * * ERROR has no payload. */ @@ -1098,36 +1098,7 @@ public: * * ERROR has no payload. */ - VERB_REQUEST_PROOF_OF_WORK = 19, - - /** - * Generic binary object access: - * <[8] 64-bit request ID> - * <[4] 32-bit index in blob to retrieve> - * <[2] 16-bit max length of block to retrieve> - * <[2] 16-bit length of blob identifier> - * <[...] blob identifier> - * - * This is used as a generic remote object retrieval mechanism. It returns - * OK if the object is accessible, INVALID_REQUEST if the index is beyond - * the size of the blob or another element is invalid, and OBJ_NOT_FOUND - * if no blob with the given identifier is available. - * - * Blob identifiers follow a de facto path-like schema, with the following - * names reserved: - * world - Current world definition (see World.hpp) - * updates.d/ - Software updates (not used yet, but reserved) - * - * OK payload: - * <[8] 64-bit request ID> - * <[4] 32-bit total length of blob> - * <[4] 32-bit index of this data in blob> - * <[...] data> - * - * ERROR payload: - * <[8] 64-bit request ID> - */ - VERB_GET_OBJECT = 20 + VERB_REQUEST_PROOF_OF_WORK = 19 }; /** diff --git a/node/Peer.cpp b/node/Peer.cpp index 111c849e..697ba75d 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -108,17 +108,16 @@ void Peer::received( // Add new path slot = &(_paths[np++]); } else { - // Replace oldest non-fixed path uint64_t slotLRmin = 0xffffffffffffffffULL; for(unsigned int p=0;preceived(now); _numPaths = np; pathIsConfirmed = true; @@ -172,12 +171,15 @@ void Peer::attemptToContactAt(const RuntimeEnvironment *RR,const InetAddress &lo outp.append(now); RR->identity.serialize(outp,false); 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->antiRec->logOutgoingZT(outp.data(),outp.size()); RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size()); } -void Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now) +RemotePath *Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now) { Mutex::Lock _l(_lock); RemotePath *const bestPath = _getBestPath(now); @@ -193,6 +195,7 @@ void Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now) bestPath->sent(now); } } + return bestPath; } void Peer::pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_t now,bool force) @@ -269,59 +272,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 dswtmp; + newWorld.serialize(dswtmp,false); + RR->node->dataStorePut("world",dswtmp.data(),dswtmp.size(),false); + } catch ( ... ) { + RR->node->dataStoreDelete("world"); + } return true; } return false; diff --git a/node/Topology.hpp b/node/Topology.hpp index 3abc27e4..6f0170f0 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -147,12 +147,19 @@ public: } /** - * @return Pair containing world ID and world timestamp (faster than world().id() etc.) + * @return Current world ID */ - inline std::pair worldIdentification() const + inline uint64_t worldId() const { - Mutex::Lock _l(_lock); - return std::pair(_world.id(),_world.timestamp()); + 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 } /** diff --git a/service/ControlPlane.cpp b/service/ControlPlane.cpp index 6e731bdc..dd755a30 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(&(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); diff --git a/world/2015-10-13.bin b/world/2015-10-13.bin new file mode 100644 index 00000000..433a7763 Binary files /dev/null and b/world/2015-10-13.bin differ diff --git a/world/2015-10-13.out b/world/2015-10-13.out new file mode 100644 index 00000000..754e0692 --- /dev/null +++ b/world/2015-10-13.out @@ -0,0 +1,6 @@ +INFO: created initial world keys: previous.c25519, current.c25519 +INFO: generating and signing id==149604618 ts==1442567945403 +INFO: wrote 494 bytes to stdout + +#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,0x4f,0xdf,0xbf,0xfc,0xbb,0x6c,0x7e,0x15,0x67,0x85,0x1b,0xb4,0x65,0x04,0x01,0xaf,0x56,0xbf,0xe7,0x63,0x9d,0x77,0xef,0xa4,0x1e,0x61,0x53,0x88,0xcb,0x8d,0x78,0xe5,0x47,0x38,0x98,0x5a,0x6c,0x8a,0xdd,0xe6,0x9c,0x65,0xdf,0x1a,0x80,0x63,0xce,0x2e,0x4d,0x48,0x24,0x3d,0x68,0x87,0x96,0x13,0x89,0xba,0x25,0x6f,0xc9,0xb0,0x9f,0x20,0xc5,0x4c,0x51,0x7b,0x30,0xb7,0x5f,0xba,0xca,0xa4,0xc5,0x48,0xa3,0x15,0xab,0x2f,0x1d,0x64,0xe8,0x04,0x42,0xb3,0x1c,0x51,0x8b,0x2a,0x04,0x01,0xf8,0xe1,0x81,0xaf,0x60,0x2f,0x70,0x3e,0xcd,0x0b,0x21,0x38,0x19,0x62,0x02,0xbd,0x0e,0x33,0x1d,0x0a,0x7b,0xf1,0xec,0xad,0xef,0x54,0xb3,0x7b,0x17,0x84,0xaa,0xda,0x0a,0x85,0x5d,0x0b,0x1c,0x05,0x83,0xb9,0x0e,0x3e,0xe3,0xb4,0xd1,0x8b,0x5b,0x64,0xf7,0xcf,0xe1,0xff,0x5d,0xc2,0x2a,0xcf,0x60,0x7b,0x09,0xb4,0xa3,0x86,0x3c,0x5a,0x7e,0x31,0xa0,0xc7,0xb4,0x86,0xe3,0x41,0x33,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}; diff --git a/world/mkworld.cpp b/world/mkworld.cpp new file mode 100644 index 00000000..baf693fc --- /dev/null +++ b/world/mkworld.cpp @@ -0,0 +1,170 @@ +/* + * 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 . + * + * -- + * + * 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 +#include +#include +#include + +#include +#include +#include + +#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 &roots,const C25519::Pair &signWith) + { + WorldMaker w; + w._id = id; + w._ts = ts; + w._updateSigningKey = sk; + w._roots = roots; + + Buffer 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, current.c25519"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 roots; + + // old US-SFO + roots.push_back(World::Root()); + roots.back().identity = Identity("7e19876aba:0:2a6e2b2318930f60eb097f70d0f4b028b2cd6d3d0c63c014b9039ff35390e41181f216fb2e6fa8d95c1ee9667156411905c3dccfea78d8c6dfafba688170b3fa"); + roots.back().stableEndpoints.push_back(InetAddress("198.199.97.220/9993")); + std::sort(roots.back().stableEndpoints.begin(),roots.back().stableEndpoints.end()); + + // old EU-PARIS + roots.push_back(World::Root()); + roots.back().identity = Identity("8841408a2e:0:bb1d31f2c323e264e9e64172c1a74f77899555ed10751cd56e86405cde118d02dffe555d462ccf6a85b5631c12350c8d5dc409ba10b9025d0f445cf449d92b1c"); + roots.back().stableEndpoints.push_back(InetAddress("107.191.46.210/9993")); + std::sort(roots.back().stableEndpoints.begin(),roots.back().stableEndpoints.end()); + + // old US-NYC + roots.push_back(World::Root()); + roots.back().identity = Identity("8acf059fe3:0:482f6ee5dfe902319b419de5bdc765209c0ecda38c4d6e4fcf0d33658398b4527dcd22f93112fb9befd02fd78bf7261b333fc105d192a623ca9e50fc60b374a5"); + roots.back().stableEndpoints.push_back(InetAddress("162.243.77.111/9993")); + std::sort(roots.back().stableEndpoints.begin(),roots.back().stableEndpoints.end()); + + // old AP-SNG + roots.push_back(World::Root()); + roots.back().identity = Identity("9d219039f3:0:01f0922a98e3b34ebcbff333269dc265d7a020aab69d72be4d4acc9c8c9294785771256cd1d942a90d1bd1d2dca3ea84ef7d85afe6611fb43ff0b74126d90a6e"); + roots.back().stableEndpoints.push_back(InetAddress("128.199.197.217/9993")); + std::sort(roots.back().stableEndpoints.begin(),roots.back().stableEndpoints.end()); + + std::sort(roots.begin(),roots.end()); + + const uint64_t id = ZT_WORLD_ID_EARTH; + const uint64_t ts = OSUtils::now(); + + // END WORLD SETUP --------------------------------------------------------- + + 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 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; + } + fwrite(outtmp.data(),outtmp.size(),1,stdout); + fflush(stdout); + + fprintf(stderr,"INFO: wrote %u bytes to stdout"ZT_EOL_S,outtmp.size()); + + fprintf(stderr,ZT_EOL_S); + fprintf(stderr,"#define ZT_DEFAULT_WORLD_LENGTH %u"ZT_EOL_S,outtmp.size()); + fprintf(stderr,"static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {"); + for(unsigned int i=0;i 0) + fprintf(stderr,","); + fprintf(stderr,"0x%.2x",(unsigned int)d[i]); + } + fprintf(stderr,"};"ZT_EOL_S); + + return 0; +} -- cgit v1.2.3 From 123c466843fb910c5496cf6218e56678bd4b43ba Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 13 Oct 2015 12:17:47 -0700 Subject: Full integration of World and World updates. --- node/IncomingPacket.cpp | 17 ++++++++++++++--- world/README.md | 6 ++++++ 2 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 world/README.md diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 3c6268ed..79a700f6 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -335,9 +335,21 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p const unsigned int vMinor = (*this)[ZT_PROTO_VERB_HELLO__OK__IDX_MINOR_VERSION]; const unsigned int vRevision = at(ZT_PROTO_VERB_HELLO__OK__IDX_REVISION); + const bool trusted = RR->topology->isRoot(peer->identity()); + InetAddress destAddr; - if ((ZT_PROTO_VERB_HELLO__OK__IDX_REVISION + 2) < size()) // ZeroTier One < 1.0.3 did not include this field - destAddr.deserialize(*this,ZT_PROTO_VERB_HELLO__OK__IDX_REVISION + 2); + 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 += destAddr.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(ptr); ptr += 2; + if (worldLen > 0) { + World w; + w.deserialize(*this,ptr); + RR->topology->worldUpdateIfValid(w); + } + } if (vProto < ZT_PROTO_VERSION_MIN) { TRACE("%s(%s): OK(HELLO) dropped, protocol version too old",source().toString().c_str(),_remoteAddress.toString().c_str()); @@ -349,7 +361,6 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p peer->addDirectLatencyMeasurment(latency); peer->setRemoteVersion(vProto,vMajor,vMinor,vRevision); - bool trusted = RR->topology->isRoot(peer->identity()); if (destAddr) RR->sa->iam(peer->address(),_remoteAddress,destAddr,trusted,RR->node->now()); } break; diff --git a/world/README.md b/world/README.md new file mode 100644 index 00000000..4e0820e6 --- /dev/null +++ b/world/README.md @@ -0,0 +1,6 @@ +World Definitions and Generator Code +====== + +This code can be used to generate a world definition. Actual generation was performed on an airgapped secure system. + +Ordinary users probably will not need to use this. -- cgit v1.2.3 From e268d9492a2357a324345fb94a3f03645a341876 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 13 Oct 2015 12:18:47 -0700 Subject: cleanup --- node/Topology.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/node/Topology.cpp b/node/Topology.cpp index cdecfdae..8b5deffc 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -28,7 +28,6 @@ #include "Constants.hpp" #include "Topology.hpp" #include "RuntimeEnvironment.hpp" -#include "Dictionary.hpp" #include "Node.hpp" #include "Buffer.hpp" -- cgit v1.2.3 From 71348f3ebbc84fe31d15bb0aa0f6b2b6e158cf28 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 13 Oct 2015 12:29:01 -0700 Subject: docs --- world/README.md | 7 +++++-- world/mkworld.cpp | 12 ++++++------ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/world/README.md b/world/README.md index 4e0820e6..fbd8a0ae 100644 --- a/world/README.md +++ b/world/README.md @@ -1,6 +1,9 @@ World Definitions and Generator Code ====== -This code can be used to generate a world definition. Actual generation was performed on an airgapped secure system. +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: + + c++ -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 -Ordinary users probably will not need to use this. diff --git a/world/mkworld.cpp b/world/mkworld.cpp index baf693fc..75230da4 100644 --- a/world/mkworld.cpp +++ b/world/mkworld.cpp @@ -50,12 +50,12 @@ #include #include -#include "node/Constants.hpp" -#include "node/World.hpp" -#include "node/C25519.hpp" -#include "node/Identity.hpp" -#include "node/InetAddress.hpp" -#include "osdep/OSUtils.hpp" +#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; -- cgit v1.2.3 From 70d8e3ad94076c51b05b4165cbd68a91806dbde7 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 13 Oct 2015 12:31:38 -0700 Subject: Expose world ID and world timestamp in ZT_NodeStatus --- include/ZeroTierOne.h | 10 ++++++++++ node/Node.cpp | 2 ++ 2 files changed, 12 insertions(+) diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 38db3222..42c904eb 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -275,6 +275,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) * diff --git a/node/Node.cpp b/node/Node.cpp index 5468f102..be37b7c7 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -345,6 +345,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; -- cgit v1.2.3 From 385f1410d24c37ef9cd8a3494a5eaa383ffd0fba Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 13 Oct 2015 12:33:15 -0700 Subject: Expose world info in JSON. --- service/ControlPlane.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/service/ControlPlane.cpp b/service/ControlPlane.cpp index dd755a30..7affb08c 100644 --- a/service/ControlPlane.cpp +++ b/service/ControlPlane.cpp @@ -360,6 +360,8 @@ unsigned int ControlPlane::handleRequest( "{\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" @@ -370,6 +372,8 @@ unsigned int ControlPlane::handleRequest( "}\n", status.address, status.publicIdentity, + status.worldId, + status.worldTimestamp, (status.online) ? "true" : "false", (_svc->tcpFallbackActive()) ? "true" : "false", ZEROTIER_ONE_VERSION_MAJOR, -- cgit v1.2.3 From 824ed99160607ddf42a520f46f65c17e4abe9bd0 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 13 Oct 2015 12:42:54 -0700 Subject: . --- node/Packet.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/node/Packet.hpp b/node/Packet.hpp index 810f5d67..e03190a2 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -59,6 +59,7 @@ * + New identity format based on hashcash design * 5 - 1.0.6 ... CURRENT * + Supports circuit test, proof of work, and echo + * + Supports in-band world (root definition) updates * + Otherwise backward compatible with 4 */ #define ZT_PROTO_VERSION 5 -- cgit v1.2.3 From 489e1a5b8339403288a4a88b91ae01cb0092ddca Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 13 Oct 2015 13:51:54 -0700 Subject: Don't keep connections up longer than the alive timeout (unless they are relays or roots) --- node/Node.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/node/Node.cpp b/node/Node.cpp index be37b7c7..d72bc73f 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -206,8 +206,10 @@ public: } } - if ((!p->doPingAndKeepalive(RR,_now))&&(stableEndpoint)) - p->attemptToContactAt(RR,InetAddress(),stableEndpoint,_now); + if ((p->alive(_now))||(upstream)) { + if ((!p->doPingAndKeepalive(RR,_now))&&(stableEndpoint)) + p->attemptToContactAt(RR,InetAddress(),stableEndpoint,_now); + } if (upstream) lastReceiveFromUpstream = std::max(p->lastReceive(),lastReceiveFromUpstream); -- cgit v1.2.3 From 719233617ca9f26c3309d608a38aadf701bb5648 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 14 Oct 2015 10:14:07 -0700 Subject: Add uint16_t key to Hashtable, and make Salsa20 zero its keyspace on destruction. --- node/Hashtable.hpp | 5 ++++- node/Salsa20.hpp | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/node/Hashtable.hpp b/node/Hashtable.hpp index beef1468..1d8d9e5d 100644 --- a/node/Hashtable.hpp +++ b/node/Hashtable.hpp @@ -382,7 +382,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/Salsa20.hpp b/node/Salsa20.hpp index a2082bea..7e4c1e53 100644 --- a/node/Salsa20.hpp +++ b/node/Salsa20.hpp @@ -12,6 +12,7 @@ #include #include "Constants.hpp" +#include "Utils.hpp" #if (!defined(ZT_SALSA20_SSE)) && (defined(__SSE2__) || defined(__WINDOWS__)) #define ZT_SALSA20_SSE 1 @@ -31,6 +32,8 @@ 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) -- cgit v1.2.3 From c312ae221f0aa339cce56c411d59d9cc9e34abc5 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 14 Oct 2015 10:45:33 -0700 Subject: Fix for world size in OK(HELLO) --- node/IncomingPacket.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 79a700f6..944e3043 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -302,7 +302,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) const unsigned int sizeAt = outp.size(); outp.addSize(2); // make room for 16-bit size field w.serialize(outp,false); - outp.setAt(sizeAt,(uint16_t)(outp.size() - sizeAt)); + outp.setAt(sizeAt,(uint16_t)(outp.size() - (sizeAt + 2))); } else { outp.append((uint16_t)0); // no world update needed } @@ -435,12 +435,12 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr { try { if (payloadLength() == ZT_ADDRESS_LENGTH) { - const SharedPtr 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->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); } else { -- cgit v1.2.3 From 619e1137480de4682bb46eabaee3ce750c5be3e8 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 14 Oct 2015 14:12:12 -0700 Subject: Work in progress on Cluster for new root infrastructure, multi-homing. --- make-mac.mk | 2 +- node/Cluster.cpp | 398 +++++++++++++++++++++++++++++++++++++++++++++++++++++ node/Cluster.hpp | 331 ++++++++++++++++++++++++++++++++++++++++++++ node/Constants.hpp | 2 +- node/Identity.hpp | 19 ++- node/Packet.hpp | 4 + node/Peer.hpp | 3 +- node/Topology.cpp | 31 +++-- node/Topology.hpp | 19 ++- objects.mk | 1 + 10 files changed, 794 insertions(+), 16 deletions(-) create mode 100644 node/Cluster.cpp create mode 100644 node/Cluster.hpp diff --git a/make-mac.mk b/make-mac.mk index 174216fb..e53212c0 100644 --- a/make-mac.mk +++ b/make-mac.mk @@ -6,7 +6,7 @@ ifeq ($(origin CXX),default) endif INCLUDES= -DEFS= +DEFS=-DZT_ENABLE_CLUSTER LIBS= ARCH_FLAGS=-arch x86_64 diff --git a/node/Cluster.cpp b/node/Cluster.cpp new file mode 100644 index 00000000..98b45265 --- /dev/null +++ b/node/Cluster.cpp @@ -0,0 +1,398 @@ +/* + * 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 . + * + * -- + * + * 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 +#include +#include +#include + +#include +#include + +#include "Cluster.hpp" +#include "RuntimeEnvironment.hpp" +#include "MulticastGroup.hpp" +#include "CertificateOfMembership.hpp" +#include "Salsa20.hpp" +#include "Poly1305.hpp" +#include "Packet.hpp" +#include "Peer.hpp" +#include "Switch.hpp" +#include "Node.hpp" + +namespace ZeroTier { + +Cluster::Cluster(const RuntimeEnvironment *renv,uint16_t id,DistanceAlgorithm da,int32_t x,int32_t y,int32_t z,void (*sendFunction)(void *,uint16_t,const void *,unsigned int),void *arg) : + RR(renv), + _sendFunction(sendFunction), + _arg(arg), + _x(x), + _y(y), + _z(z), + _da(da), + _id(id) +{ + 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)); +} + +void Cluster::handleIncomingStateMessage(const void *msg,unsigned int len) +{ + Buffer 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(msg)[i]; + Salsa20 s20(keytmp,256,reinterpret_cast(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(msg) + 24,len - 24,polykey); + + // Check first 8 bytes of MAC against 64-bit MAC in stream + if (!Utils::secureEq(mac,reinterpret_cast(msg) + 16,8)) + return; + + // Decrypt! + dmsg.setSize(len - 16); + s20.decrypt12(reinterpret_cast(msg) + 16,const_cast(dmsg.data()),dmsg.size()); + } + + if (dmsg.size() < 2) + return; + const uint16_t fromMemberId = dmsg.at(0); + unsigned int ptr = 2; + + _Member &m = _members[fromMemberId]; + Mutex::Lock mlck(m.lock); + + m.lastReceivedFrom = RR->node->now(); + + try { + while (ptr < dmsg.size()) { + const unsigned int mlen = dmsg.at(ptr); ptr += 2; + const unsigned int nextPtr = ptr + mlen; + + int mtype = -1; + try { + switch((StateMessageType)(mtype = (int)dmsg[ptr++])) { + default: + break; + + case STATE_MESSAGE_ALIVE: { + ptr += 7; // skip version stuff, not used yet + m.x = dmsg.at(ptr); ptr += 4; + m.y = dmsg.at(ptr); ptr += 4; + m.z = dmsg.at(ptr); ptr += 4; + ptr += 8; // skip local clock, not used + m.load = dmsg.at(ptr); ptr += 8; + ptr += 8; // skip flags, unused + m.physicalAddressCount = dmsg[ptr++]; + if (m.physicalAddressCount > ZT_CLUSTER_MEMBER_MAX_PHYSICAL_ADDRS) + m.physicalAddressCount = ZT_CLUSTER_MEMBER_MAX_PHYSICAL_ADDRS; + for(unsigned int i=0;inode->now(); + } break; + + case STATE_MESSAGE_HAVE_PEER: { + try { + Identity id; + ptr += id.deserialize(dmsg,ptr); + RR->topology->saveIdentity(id); + + { // Add or update peer affinity entry + _PeerAffinity pa(id.address(),fromMemberId,RR->node->now()); + Mutex::Lock _l2(_peerAffinities_m); + std::vector<_PeerAffinity>::iterator i(std::lower_bound(_peerAffinities.begin(),_peerAffinities.end(),pa)); // O(log(n)) + if ((i != _peerAffinities.end())&&(i->key == pa.key)) { + i->timestamp = pa.timestamp; + } else { + _peerAffinities.push_back(pa); + std::sort(_peerAffinities.begin(),_peerAffinities.end()); // probably a more efficient way to insert but okay for now + } + } + } catch ( ... ) { + // ignore invalid identities + } + } break; + + case STATE_MESSAGE_MULTICAST_LIKE: { + const uint64_t nwid = dmsg.at(ptr); ptr += 8; + const Address address(dmsg.field(ptr,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); ptr += ZT_ADDRESS_LENGTH; + const MAC mac(dmsg.field(ptr,6),6); ptr += 6; + const uint32_t adi = dmsg.at(ptr); ptr += 4; + RR->mc->add(RR->node->now(),nwid,MulticastGroup(mac,adi),address); + } break; + + case STATE_MESSAGE_COM: { + // TODO: not used yet + } break; + + case STATE_MESSAGE_RELAY: { + const unsigned int numRemotePeerPaths = dmsg[ptr++]; + InetAddress remotePeerPaths[256]; // size is 8-bit, so 256 is max + for(unsigned int i=0;i(ptr); ptr += 2; + const void *packet = (const void *)dmsg.field(ptr,packetLen); ptr += packetLen; + + if (packetLen >= ZT_PROTO_MIN_FRAGMENT_LENGTH) { // ignore anything too short to contain a dest address + const Address destinationAddress(reinterpret_cast(packet) + 8,ZT_ADDRESS_LENGTH); + SharedPtr destinationPeer(RR->topology->getPeer(destinationAddress)); + if (destinationPeer) { + RemotePath *destinationPath = destinationPeer->send(RR,packet,packetLen,RR->node->now()); + if ((destinationPath)&&(numRemotePeerPaths > 0)&&(packetLen >= 18)&&(reinterpret_cast(packet)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR] == ZT_PACKET_FRAGMENT_INDICATOR)) { + // If remote peer paths were sent with this relayed packet, we do + // RENDEZVOUS. It's handled here for cluster-relayed packets since + // we don't have both Peer records so this is a different path. + + const Address remotePeerAddress(reinterpret_cast(packet) + 13,ZT_ADDRESS_LENGTH); + + InetAddress bestDestV4,bestDestV6; + destinationPeer->getBestActiveAddresses(RR->node->now(),bestDestV4,bestDestV6); + InetAddress bestRemoteV4,bestRemoteV6; + for(unsigned int i=0;iidentity.address(),Packet::VERB_RENDEZVOUS); + rendezvousForDest.append((uint8_t)0); + remotePeerAddress.appendTo(rendezvousForDest); + + Buffer<2048> rendezvousForOtherEnd; + rendezvousForOtherEnd.addSize(2); // leave room for payload size + rendezvousForOtherEnd.append((uint8_t)STATE_MESSAGE_PROXY_SEND); + remotePeerAddress.appendTo(rendezvousForOtherEnd); + rendezvousForOtherEnd.append((uint8_t)Packet::VERB_RENDEZVOUS); + const unsigned int rendezvousForOtherEndPayloadSizePtr = rendezvousForOtherEnd.size(); + rendezvousForOtherEnd.addSize(2); // space for actual packet payload length + rendezvousForOtherEnd.append((uint8_t)0); // flags == 0 + destinationAddress.appendTo(rendezvousForOtherEnd); + + bool haveMatch = false; + if ((bestDestV6)&&(bestRemoteV6)) { + haveMatch = true; + + rendezvousForDest.append((uint16_t)bestRemoteV6.port()); + rendezvousForDest.append((uint8_t)16); + rendezvousForDest.append(bestRemoteV6.rawIpData(),16); + + rendezvousForOtherEnd.append((uint16_t)bestDestV6.port()); + rendezvousForOtherEnd.append((uint8_t)16); + rendezvousForOtherEnd.append(bestDestV6.rawIpData(),16); + rendezvousForOtherEnd.setAt(rendezvousForOtherEndPayloadSizePtr,(uint16_t)(9 + 16)); + } else if ((bestDestV4)&&(bestRemoteV4)) { + haveMatch = true; + + rendezvousForDest.append((uint16_t)bestRemoteV4.port()); + rendezvousForDest.append((uint8_t)4); + rendezvousForDest.append(bestRemoteV4.rawIpData(),4); + + rendezvousForOtherEnd.append((uint16_t)bestDestV4.port()); + rendezvousForOtherEnd.append((uint8_t)4); + rendezvousForOtherEnd.append(bestDestV4.rawIpData(),4); + rendezvousForOtherEnd.setAt(rendezvousForOtherEndPayloadSizePtr,(uint16_t)(9 + 4)); + } + + if (haveMatch) { + RR->sw->send(rendezvousForDest,true,0); + rendezvousForOtherEnd.setAt(0,(uint16_t)(rendezvousForOtherEnd.size() - 2)); + _send(fromMemberId,rendezvousForOtherEnd.data(),rendezvousForOtherEnd.size()); + } + } + } + } + } break; + + case STATE_MESSAGE_PROXY_SEND: { + const Address rcpt(dmsg.field(ptr,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); + const Packet::Verb verb = (Packet::Verb)dmsg[ptr++]; + const unsigned int len = dmsg.at(ptr); ptr += 2; + Packet outp(rcpt,RR->identity.address(),verb); + outp.append(dmsg.field(ptr,len),len); + RR->sw->send(outp,true,0); + } 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::replicateHavePeer(const Address &peerAddress) +{ +} + +void Cluster::replicateMulticastLike(uint64_t nwid,const Address &peerAddress,const MulticastGroup &group) +{ +} + +void Cluster::replicateCertificateOfNetworkMembership(const CertificateOfMembership &com) +{ +} + +void Cluster::doPeriodicTasks() +{ + // Go ahead and flush whenever possible right now + { + Mutex::Lock _l(_memberIds_m); + for(std::vector::const_iterator mid(_memberIds.begin());mid!=_memberIds.end();++mid) { + Mutex::Lock _l2(_members[*mid].lock); + _flush(*mid); + } + } +} + +void Cluster::addMember(uint16_t memberId) +{ + Mutex::Lock _l2(_members[memberId].lock); + + Mutex::Lock _l(_memberIds_m); + _memberIds.push_back(memberId); + std::sort(_memberIds.begin(),_memberIds.end()); + + // 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 +} + +void Cluster::_send(uint16_t memberId,const void *msg,unsigned int len) +{ + _Member &m = _members[memberId]; + // assumes m.lock is locked! + for(;;) { + if ((m.q.size() + len) > ZT_CLUSTER_MAX_MESSAGE_LENGTH) + _flush(memberId); + else { + m.q.append(msg,len); + break; + } + } +} + +void Cluster::_flush(uint16_t memberId) +{ + _Member &m = _members[memberId]; + // assumes m.lock is locked! + if (m.q.size() > 24) { + // 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(m.q.data()) + 24,const_cast(reinterpret_cast(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(m.q.data()) + 24,m.q.size() - 24,polykey); + memcpy(m.q.field(16,8),mac,8); + + // Send! + _sendFunction(_arg,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 + } +} + +} // namespace ZeroTier + +#endif // ZT_ENABLE_CLUSTER diff --git a/node/Cluster.hpp b/node/Cluster.hpp new file mode 100644 index 00000000..13d9e2f5 --- /dev/null +++ b/node/Cluster.hpp @@ -0,0 +1,331 @@ +/* + * 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 . + * + * -- + * + * 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 +#include + +#include "Constants.hpp" +#include "Address.hpp" +#include "InetAddress.hpp" +#include "SHA512.hpp" +#include "Utils.hpp" +#include "Buffer.hpp" +#include "Mutex.hpp" + +/** + * Timeout for cluster members being considered "alive" + */ +#define ZT_CLUSTER_TIMEOUT ZT_PEER_ACTIVITY_TIMEOUT + +/** + * Maximum cluster message length in bytes + * + * Cluster nodes speak via TCP, with data encapsulated into individually + * encrypted and authenticated messages. The maximum message size is + * 65535 (0xffff) since the TCP stream uses 16-bit message size headers + * (and this is a reasonable chunk size anyway). + */ +#define ZT_CLUSTER_MAX_MESSAGE_LENGTH 65535 + +/** + * Maximum number of physical addresses we will cache for a cluster member + */ +#define ZT_CLUSTER_MEMBER_MAX_PHYSICAL_ADDRS 8 + +namespace ZeroTier { + +class RuntimeEnvironment; +class CertificateOfMembership; +class MulticastGroup; + +/** + * 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: + /** + * Which distance algorithm is this cluster using? + */ + enum DistanceAlgorithm + { + /** + * Simple linear distance in three dimensions + */ + DISTANCE_SIMPLE = 0, + + /** + * Haversine formula using X,Y as lat,long and ignoring Z + */ + DISTANCE_HAVERSINE = 1 + }; + + /** + * State message types + */ + enum StateMessageType + { + STATE_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] flags (currently unused, must be zero)> + * <[1] number of preferred ZeroTier endpoints> + * <[...] InetAddress(es) of preferred ZeroTier endpoint(s)> + */ + STATE_MESSAGE_ALIVE = 1, + + /** + * Cluster member has this peer: + * <[...] binary serialized peer identity> + */ + STATE_MESSAGE_HAVE_PEER = 2, + + /** + * Peer subscription to multicast group: + * <[8] network ID> + * <[5] peer ZeroTier address> + * <[6] MAC address of multicast group> + * <[4] 32-bit multicast group ADI> + */ + STATE_MESSAGE_MULTICAST_LIKE = 3, + + /** + * Certificate of network membership for a peer: + * <[...] serialized COM> + */ + STATE_MESSAGE_COM = 4, + + /** + * Relay a packet to a peer: + * <[1] 8-bit number of sending peer active path addresses> + * <[...] series of serialized InetAddresses of sending peer's paths> + * <[2] 16-bit packet length> + * <[...] packet or packet fragment> + */ + STATE_MESSAGE_RELAY = 5, + + /** + * Request to 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). + */ + STATE_MESSAGE_PROXY_SEND = 6 + }; + + /** + * Construct a new cluster + * + * @param renv Runtime environment + * @param id This member's ID in the cluster + * @param da Distance algorithm this cluster uses to compute distance and hand off peers + * @param x My X + * @param y My Y + * @param z My Z + * @param sendFunction Function to call to send messages to other cluster members + * @param arg First argument to sendFunction + */ + Cluster( + const RuntimeEnvironment *renv, + uint16_t id, + DistanceAlgorithm da, + int32_t x, + int32_t y, + int32_t z, + void (*sendFunction)(void *,uint16_t,const void *,unsigned int), + void *arg); + + ~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); + + /** + * Advertise to the cluster that we have this peer + * + * @param peerAddress Peer address that we have + */ + void replicateHavePeer(const Address &peerAddress); + + /** + * Advertise a multicast LIKE to the cluster + * + * @param nwid Network ID + * @param peerAddress Peer address that sent LIKE + * @param group Multicast group + */ + void replicateMulticastLike(uint64_t nwid,const Address &peerAddress,const MulticastGroup &group); + + /** + * Advertise a network COM to the cluster + * + * @param com Certificate of network membership (contains peer and network ID) + */ + void replicateCertificateOfNetworkMembership(const CertificateOfMembership &com); + + /** + * This should be called no less frequently than once every 10 seconds. + */ + void doPeriodicTasks(); + + /** + * Add a member ID to this cluster + * + * @param memberId Member ID + */ + void addMember(uint16_t memberId); + +private: + void _send(uint16_t memberId,const void *msg,unsigned int len); + void _flush(uint16_t memberId); + + // These are initialized in the constructor and remain static + uint16_t _masterSecret[ZT_SHA512_DIGEST_LEN / sizeof(uint16_t)]; + unsigned char _key[ZT_PEER_SECRET_KEY_LENGTH]; + const RuntimeEnvironment *RR; + void (*_sendFunction)(void *,uint16_t,const void *,unsigned int); + void *_arg; + const int32_t _x; + const int32_t _y; + const int32_t _z; + const DistanceAlgorithm _da; + const uint16_t _id; + + struct _Member + { + unsigned char key[ZT_PEER_SECRET_KEY_LENGTH]; + + uint64_t lastReceivedFrom; + uint64_t lastReceivedAliveAnnouncement; + uint64_t lastSentTo; + uint64_t lastAnnouncedAliveTo; + + uint64_t load; + int32_t x,y,z; + + InetAddress physicalAddresses[ZT_CLUSTER_MEMBER_MAX_PHYSICAL_ADDRS]; + unsigned int physicalAddressCount; + + Buffer q; + + Mutex lock; + + _Member() : + lastReceivedFrom(0), + lastReceivedAliveAnnouncement(0), + lastSentTo(0), + lastAnnouncedAliveTo(0), + load(0), + x(0), + y(0), + z(0), + physicalAddressCount(0) {} + + ~_Member() { Utils::burn(key,sizeof(key)); } + }; + + _Member _members[65536]; // cluster IDs can be from 0 to 65535 (16-bit) + + std::vector _memberIds; + Mutex _memberIds_m; + + // Record tracking which members have which peers and how recently they claimed this + struct _PeerAffinity + { + _PeerAffinity(const Address &a,uint16_t mid,uint64_t ts) : + key((a.toInt() << 16) | (uint64_t)mid), + timestamp(ts) {} + + uint64_t key; + uint64_t timestamp; + + inline Address address() const throw() { return Address(key >> 16); } + inline uint16_t clusterMemberId() const throw() { return (uint16_t)(key & 0xffff); } + + inline bool operator<(const _PeerAffinity &pi) const throw() { return (key < pi.key); } + }; + + // A memory-efficient packed map of _PeerAffinity records searchable with std::binary_search() and std::lower_bound() + std::vector<_PeerAffinity> _peerAffinities; + Mutex _peerAffinities_m; +}; + +} // namespace ZeroTier + +#endif // ZT_ENABLE_CLUSTER + +#endif diff --git a/node/Constants.hpp b/node/Constants.hpp index 9ab390eb..afcb4e30 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -182,7 +182,7 @@ #define ZT_FRAGMENTED_PACKET_RECEIVE_TIMEOUT 1000 /** - * 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 diff --git a/node/Identity.hpp b/node/Identity.hpp index 19bb2e1f..6c33e74f 100644 --- a/node/Identity.hpp +++ b/node/Identity.hpp @@ -38,6 +38,7 @@ #include "Address.hpp" #include "C25519.hpp" #include "Buffer.hpp" +#include "SHA512.hpp" namespace ZeroTier { @@ -91,8 +92,7 @@ public: } template - Identity(const Buffer &b,unsigned int startAt = 0) - throw(std::out_of_range,std::invalid_argument) : + Identity(const Buffer &b,unsigned int startAt = 0) : _privateKey((C25519::Private *)0) { deserialize(b,startAt); @@ -137,6 +137,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) * diff --git a/node/Packet.hpp b/node/Packet.hpp index e03190a2..0e8426b6 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -623,6 +623,10 @@ 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, diff --git a/node/Peer.hpp b/node/Peer.hpp index cabf0793..0139f386 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -560,7 +560,8 @@ private: void _sortPaths(const uint64_t now); RemotePath *_getBestPath(const uint64_t now); - unsigned char _key[ZT_PEER_SECRET_KEY_LENGTH]; + unsigned char _key[ZT_PEER_SECRET_KEY_LENGTH]; // computed with key agreement, not serialized + uint64_t _lastUsed; uint64_t _lastReceive; // direct or indirect uint64_t _lastUnicastFrame; diff --git a/node/Topology.cpp b/node/Topology.cpp index 8b5deffc..2b973386 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -136,7 +136,7 @@ SharedPtr Topology::addPeer(const SharedPtr &peer) SharedPtr &p = _peers.set(peer->address(),peer); p->use(now); - _saveIdentity(p->identity()); + saveIdentity(p->identity()); return p; } @@ -172,6 +172,26 @@ SharedPtr Topology::getPeer(const Address &zta) return SharedPtr(); } +Identity Topology::getIdentity(const Address &zta) +{ + { + Mutex::Lock _l(_lock); + SharedPtr &ap = _peers[zta]; + if (ap) + return ap->identity(); + } + return _getIdentity(zta); +} + +void saveIdentity(const Identity &id) +{ + 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); + } +} + SharedPtr Topology::getBestRoot(const Address *avoid,unsigned int avoidCount,bool strictAvoid) { SharedPtr bestRoot; @@ -315,15 +335,6 @@ Identity Topology::_getIdentity(const Address &zta) return Identity(); } -void Topology::_saveIdentity(const Identity &id) -{ - 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); - } -} - void Topology::_setWorld(const World &newWorld) { // assumed _lock is locked (or in constructor) diff --git a/node/Topology.hpp b/node/Topology.hpp index 6f0170f0..9e9ccc01 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -78,6 +78,24 @@ public: */ SharedPtr getPeer(const Address &zta); + /** + * 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); + /** * @return Vector of peers that are root servers */ @@ -210,7 +228,6 @@ public: private: Identity _getIdentity(const Address &zta); - void _saveIdentity(const Identity &id); void _setWorld(const World &newWorld); const RuntimeEnvironment *RR; diff --git a/objects.mk b/objects.mk index 64e5cfa7..10e0c334 100644 --- a/objects.mk +++ b/objects.mk @@ -4,6 +4,7 @@ OBJS=\ ext/http-parser/http_parser.o \ node/C25519.o \ node/CertificateOfMembership.o \ + node/Cluster.o \ node/Dictionary.o \ node/Identity.o \ node/IncomingPacket.o \ -- cgit v1.2.3 From 59389b3dcefa00541ec923ab091d400b941d6c47 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 14 Oct 2015 14:17:55 -0700 Subject: Untested cluster code, not enabled. --- make-mac.mk | 2 +- node/Cluster.cpp | 8 ++++++-- node/Topology.cpp | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/make-mac.mk b/make-mac.mk index e53212c0..174216fb 100644 --- a/make-mac.mk +++ b/make-mac.mk @@ -6,7 +6,7 @@ ifeq ($(origin CXX),default) endif INCLUDES= -DEFS=-DZT_ENABLE_CLUSTER +DEFS= LIBS= ARCH_FLAGS=-arch x86_64 diff --git a/node/Cluster.cpp b/node/Cluster.cpp index 98b45265..8a942cb0 100644 --- a/node/Cluster.cpp +++ b/node/Cluster.cpp @@ -195,8 +195,12 @@ void Cluster::handleIncomingStateMessage(const void *msg,unsigned int len) const Address destinationAddress(reinterpret_cast(packet) + 8,ZT_ADDRESS_LENGTH); SharedPtr destinationPeer(RR->topology->getPeer(destinationAddress)); if (destinationPeer) { - RemotePath *destinationPath = destinationPeer->send(RR,packet,packetLen,RR->node->now()); - if ((destinationPath)&&(numRemotePeerPaths > 0)&&(packetLen >= 18)&&(reinterpret_cast(packet)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR] == ZT_PACKET_FRAGMENT_INDICATOR)) { + if ( + (destinationPeer->send(RR,packet,packetLen,RR->node->now()))&& + (numRemotePeerPaths > 0)&& + (packetLen >= 18)&& + (reinterpret_cast(packet)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR] == ZT_PACKET_FRAGMENT_INDICATOR) + ) { // If remote peer paths were sent with this relayed packet, we do // RENDEZVOUS. It's handled here for cluster-relayed packets since // we don't have both Peer records so this is a different path. diff --git a/node/Topology.cpp b/node/Topology.cpp index 2b973386..a3558558 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -183,7 +183,7 @@ Identity Topology::getIdentity(const Address &zta) return _getIdentity(zta); } -void saveIdentity(const Identity &id) +void Topology::saveIdentity(const Identity &id) { if (id) { char p[128]; -- cgit v1.2.3 From 9ece8c465e4d98770e24f08af97fa1b380e7d9e0 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 14 Oct 2015 15:49:41 -0700 Subject: decrypt fix --- node/Cluster.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/node/Cluster.cpp b/node/Cluster.cpp index 8a942cb0..c08bf002 100644 --- a/node/Cluster.cpp +++ b/node/Cluster.cpp @@ -108,8 +108,8 @@ void Cluster::handleIncomingStateMessage(const void *msg,unsigned int len) return; // Decrypt! - dmsg.setSize(len - 16); - s20.decrypt12(reinterpret_cast(msg) + 16,const_cast(dmsg.data()),dmsg.size()); + dmsg.setSize(len - 24); + s20.decrypt12(reinterpret_cast(msg) + 24,const_cast(dmsg.data()),dmsg.size()); } if (dmsg.size() < 2) @@ -343,6 +343,7 @@ void Cluster::addMember(uint16_t memberId) 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); } void Cluster::_send(uint16_t memberId,const void *msg,unsigned int len) @@ -363,7 +364,7 @@ void Cluster::_flush(uint16_t memberId) { _Member &m = _members[memberId]; // assumes m.lock is locked! - if (m.q.size() > 24) { + if (m.q.size() > 26) { // 16-byte IV + 8-byte MAC + 2-byte cluster member ID (latter two bytes are inside crypto envelope) // Create key from member's key and IV char keytmp[32]; memcpy(keytmp,m.key,32); @@ -394,6 +395,7 @@ void Cluster::_flush(uint16_t memberId) Utils::getSecureRandom(iv,16); m.q.append(iv,16); m.q.addSize(8); // room for MAC + m.q.append((uint16_t)_id); } } -- cgit v1.2.3 From a775ee7d315fd960f472a6e655c8fda92e53f44a Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 14 Oct 2015 16:21:39 -0700 Subject: . --- make-linux.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/make-linux.mk b/make-linux.mk index 2ef9b985..5e0a2072 100644 --- a/make-linux.mk +++ b/make-linux.mk @@ -29,7 +29,7 @@ endif UNAME_M=$(shell uname -m) INCLUDES= -DEFS= +DEFS=-DZT_ENABLE_CLUSTER LDLIBS?= include objects.mk -- cgit v1.2.3 From 2debde3451838f62ed9b53d9b0086f7112416636 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 15 Oct 2015 07:22:17 -0700 Subject: GitHub issue #235, and I also see no reason not to communicate with people from other Worlds. --- node/Constants.hpp | 5 +++++ node/IncomingPacket.cpp | 31 +++++++++++++++---------------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/node/Constants.hpp b/node/Constants.hpp index afcb4e30..a60b76eb 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -347,6 +347,11 @@ */ #define ZT_MAX_BRIDGE_SPAM 16 +/** + * Maximum number of endpoints to contact per address type (to limit pushes like GitHub issue #235) + */ +#define ZT_PUSH_DIRECT_PATHS_MAX_ENDPOINTS_PER_TYPE 8 + /** * A test pseudo-network-ID that can be joined * diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 944e3043..d444258d 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -296,22 +296,18 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION); _remoteAddress.serialize(outp); - if ((worldId != ZT_WORLD_ID_NULL)&&(worldId == RR->topology->worldId())) { - if (RR->topology->worldTimestamp() > worldTimestamp) { - 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(sizeAt,(uint16_t)(outp.size() - (sizeAt + 2))); - } else { - outp.append((uint16_t)0); // no world update needed - } - - outp.armor(peer->key(),true); - RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); + 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(sizeAt,(uint16_t)(outp.size() - (sizeAt + 2))); } else { - TRACE("dropped HELLO from %s(%s): world ID mismatch: peer is %llu and we are %llu",source().toString().c_str(),_remoteAddress.toString().c_str(),worldId,RR->topology->worldId()); + outp.append((uint16_t)0); // no world update needed } + + outp.armor(peer->key(),true); + RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); } catch ( ... ) { TRACE("dropped HELLO from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); } @@ -867,6 +863,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha try { unsigned int count = at(ZT_PACKET_IDX_PAYLOAD); unsigned int ptr = ZT_PACKET_IDX_PAYLOAD + 2; + unsigned int v4Count = 0,v6Count = 0; while (count--) { // if ptr overflows Buffer will throw // TODO: some flags are not yet implemented @@ -882,14 +879,16 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha InetAddress a(field(ptr,4),4,at(ptr + 4)); if ( ((flags & 0x01) == 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 (v4Count++ < ZT_PUSH_DIRECT_PATHS_MAX_ENDPOINTS_PER_TYPE) + peer->attemptToContactAt(RR,_localAddress,a,RR->node->now()); } } break; case 6: { InetAddress a(field(ptr,16),16,at(ptr + 16)); if ( ((flags & 0x01) == 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 (v6Count++ < ZT_PUSH_DIRECT_PATHS_MAX_ENDPOINTS_PER_TYPE) + peer->attemptToContactAt(RR,_localAddress,a,RR->node->now()); } } break; } -- cgit v1.2.3 From 2229e91b57676c1218b550749a2108372e0f37ad Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 16 Oct 2015 10:10:12 -0700 Subject: IPv6 support fixes. --- node/Node.cpp | 39 +++++++++++++++++++++++++++++---------- node/Peer.cpp | 47 +++++++++++++++++++++++++++++++++++------------ node/Peer.hpp | 8 +++++--- 3 files changed, 69 insertions(+), 25 deletions(-) diff --git a/node/Node.cpp b/node/Node.cpp index d72bc73f..5aa4b7d3 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -186,33 +186,52 @@ public: inline void operator()(Topology &t,const SharedPtr &p) { bool upstream = false; - InetAddress stableEndpoint; + 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::const_iterator r(_world.roots().begin());r!=_world.roots().end();++r) { if (r->identity.address() == p->address()) { - if (r->stableEndpoints.size() > 0) - stableEndpoint = r->stableEndpoints[(unsigned long)RR->node->prng() % r->stableEndpoints.size()]; upstream = true; + for(unsigned long k=0,ptr=RR->node->prng();kstableEndpoints.size();++k) { + const InetAddress &addr = r->stableEndpoints[ptr++ % r->stableEndpoints.size()]; + if (!stableEndpoint4) { + if (addr.ss_family == AF_INET) + stableEndpoint4 = addr; + } else if (!stableEndpoint6) { + if (addr.ss_family == AF_INET6) + stableEndpoint6 = addr; + } else break; // have both! + } break; } } + // If this is a network preferred relay, also always ping and if a stable endpoint is specified use that if not alive if (!upstream) { for(std::vector< std::pair >::const_iterator r(_relays.begin());r!=_relays.end();++r) { if (r->first == p->address()) { - stableEndpoint = r->second; + 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 ((p->alive(_now))||(upstream)) { - if ((!p->doPingAndKeepalive(RR,_now))&&(stableEndpoint)) - p->attemptToContactAt(RR,InetAddress(),stableEndpoint,_now); - } - - if (upstream) + 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. + if ((!p->doPingAndKeepalive(RR,_now,AF_INET))&&(stableEndpoint4)) + p->attemptToContactAt(RR,InetAddress(),stableEndpoint4,_now); + if ((!p->doPingAndKeepalive(RR,_now,AF_INET6))&&(stableEndpoint6)) + p->attemptToContactAt(RR,InetAddress(),stableEndpoint6,_now); lastReceiveFromUpstream = std::max(p->lastReceive(),lastReceiveFromUpstream); + } else if (p->alive(_now)) { + // Normal nodes get their preferred link kept alive if the node has generated frame traffic recently + p->doPingAndKeepalive(RR,_now,0); + } } private: diff --git a/node/Peer.cpp b/node/Peer.cpp index 697ba75d..becc77f9 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -179,23 +179,31 @@ void Peer::attemptToContactAt(const RuntimeEnvironment *RR,const InetAddress &lo RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size()); } -RemotePath *Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now) +bool Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now,int inetAddressFamily) { + RemotePath *p = (RemotePath *)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) after %llums/%llums send/receive inactivity",_id.address().toString().c_str(),bestPath->address().toString().c_str(),now - bestPath->lastSend(),now - bestPath->lastReceived()); - attemptToContactAt(RR,bestPath->localAddress(),bestPath->address(),now); - bestPath->sent(now); - } else if (((now - bestPath->lastSend()) >= ZT_NAT_KEEPALIVE_DELAY)&&(!bestPath->reliable())) { - TRACE("NAT keepalive %s(%s) after %llums/%llums send/receive inactivity",_id.address().toString().c_str(),bestPath->address().toString().c_str(),now - bestPath->lastSend(),now - bestPath->lastReceived()); + 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()); + attemptToContactAt(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 - 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); } + return true; } - return bestPath; + return false; } void Peer::pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_t now,bool force) @@ -465,4 +473,19 @@ RemotePath *Peer::_getBestPath(const uint64_t now) return (RemotePath *)0; } +RemotePath *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 (RemotePath *)0; +} + } // namespace ZeroTier diff --git a/node/Peer.hpp b/node/Peer.hpp index 0139f386..4fb399c5 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -130,7 +130,7 @@ 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 direct paths @@ -178,9 +178,10 @@ public: * * @param RR Runtime environment * @param now Current time - * @return Current best path or NULL if no active paths + * @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 */ - RemotePath *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 @@ -559,6 +560,7 @@ public: private: void _sortPaths(const uint64_t now); RemotePath *_getBestPath(const uint64_t now); + RemotePath *_getBestPath(const uint64_t now,int inetAddressFamily); unsigned char _key[ZT_PEER_SECRET_KEY_LENGTH]; // computed with key agreement, not serialized -- cgit v1.2.3 From 5ce3aac929ef217f3e813b5bc948dd28d021835f Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 16 Oct 2015 10:28:09 -0700 Subject: Add rate limit on receive of DIRECT_PATH_PUSH to prevent DOS exploitation. --- node/Constants.hpp | 7 ++++++- node/IncomingPacket.cpp | 7 +++++++ node/Peer.cpp | 7 ++++--- node/Peer.hpp | 32 ++++++++++++++++++++++---------- 4 files changed, 39 insertions(+), 14 deletions(-) diff --git a/node/Constants.hpp b/node/Constants.hpp index a60b76eb..e45602f7 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -322,7 +322,12 @@ /** * Interval between direct path pushes in milliseconds */ -#define ZT_DIRECT_PATH_PUSH_INTERVAL 300000 +#define ZT_DIRECT_PATH_PUSH_INTERVAL 120000 + +/** + * Minimum interval between direct path pushes from a given peer or we will ignore them + */ +#define ZT_DIRECT_PATH_PUSH_MIN_RECEIVE_INTERVAL 2500 /** * How long (max) to remember network certificates of membership? diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index d444258d..4386e370 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -861,6 +861,13 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const SharedPtr &peer) { try { + const uint64_t now = RR->node->now(); + if ((now - peer->lastDirectPathPushReceived()) >= ZT_DIRECT_PATH_PUSH_MIN_RECEIVE_INTERVAL) { + TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): too frequent!",source().toString().c_str(),_remoteAddress.toString().c_str()); + return true; + } + peer->setLastDirectPathPushReceived(now); + unsigned int count = at(ZT_PACKET_IDX_PAYLOAD); unsigned int ptr = ZT_PACKET_IDX_PAYLOAD + 2; unsigned int v4Count = 0,v6Count = 0; diff --git a/node/Peer.cpp b/node/Peer.cpp index becc77f9..8c5c5783 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -52,7 +52,8 @@ Peer::Peer(const Identity &myIdentity,const Identity &peerIdentity) _lastMulticastFrame(0), _lastAnnouncedTo(0), _lastPathConfirmationSent(0), - _lastDirectPathPush(0), + _lastDirectPathPushSent(0), + _lastDirectPathPushReceived(0), _lastPathSort(0), _vMajor(0), _vMinor(0), @@ -210,8 +211,8 @@ void Peer::pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_ { 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 dps(RR->node->directPaths()); if (dps.empty()) diff --git a/node/Peer.hpp b/node/Peer.hpp index 4fb399c5..043519d4 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -408,6 +408,16 @@ public: */ bool needsOurNetworkMembershipCertificate(uint64_t nwid,uint64_t now,bool updateLastPushedTime); + /** + * @return Time last direct path push was received + */ + inline uint64_t lastDirectPathPushReceived() const throw() { return _lastDirectPathPushReceived; } + + /** + * @param t New time of last direct path push received + */ + inline void setLastDirectPathPushReceived(uint64_t t) throw() { _lastDirectPathPushReceived = t; } + /** * Perform periodic cleaning operations */ @@ -438,10 +448,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)1); // version of serialized Peer data _id.serialize(b,false); @@ -451,7 +461,8 @@ 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)_lastDirectPathPushReceived); b.append((uint64_t)_lastPathSort); b.append((uint16_t)_vProto); b.append((uint16_t)_vMajor); @@ -486,7 +497,7 @@ public: } } - b.setAt(atPos,(uint32_t)(b.size() - atPos)); // set size + b.setAt(recSizePos,(uint32_t)((b.size() - 4) - recSizePos)); // set size } /** @@ -500,13 +511,12 @@ public: template static inline SharedPtr deserializeNew(const Identity &myIdentity,const Buffer &b,unsigned int &p) { - const uint32_t recSize = b.template at(p); + const uint32_t recSize = b.template at(p); p += 4; if ((p + recSize) > b.size()) return SharedPtr(); // size invalid - p += 4; - if (b.template at(p) != 1) + if (b.template at(p) != 1) return SharedPtr(); // version mismatch - p += 4; + p += 2; Identity npid; p += npid.deserialize(b,p); @@ -521,7 +531,8 @@ public: np->_lastMulticastFrame = b.template at(p); p += 8; np->_lastAnnouncedTo = b.template at(p); p += 8; np->_lastPathConfirmationSent = b.template at(p); p += 8; - np->_lastDirectPathPush = b.template at(p); p += 8; + np->_lastDirectPathPushSent = b.template at(p); p += 8; + np->_lastDirectPathPushReceived = b.template at(p); p += 8; np->_lastPathSort = b.template at(p); p += 8; np->_vProto = b.template at(p); p += 2; np->_vMajor = b.template at(p); p += 2; @@ -570,7 +581,8 @@ private: uint64_t _lastMulticastFrame; uint64_t _lastAnnouncedTo; uint64_t _lastPathConfirmationSent; - uint64_t _lastDirectPathPush; + uint64_t _lastDirectPathPushSent; + uint64_t _lastDirectPathPushReceived; uint64_t _lastPathSort; uint16_t _vProto; uint16_t _vMajor; -- cgit v1.2.3 From f9f60f89d95e43e5c439bf7c86b015e1b41a2f14 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 16 Oct 2015 10:45:58 -0700 Subject: Peer save/restore fix. --- node/Peer.hpp | 8 ++++---- node/Topology.cpp | 31 ++++++++++--------------------- 2 files changed, 14 insertions(+), 25 deletions(-) diff --git a/node/Peer.hpp b/node/Peer.hpp index 043519d4..7e7e7f46 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -470,7 +470,7 @@ public: b.append((uint16_t)_vRevision); b.append((uint32_t)_latency); - b.append((uint32_t)_numPaths); + b.append((uint16_t)_numPaths); for(unsigned int i=0;i<_numPaths;++i) _paths[i].serialize(b); @@ -497,7 +497,7 @@ public: } } - b.setAt(recSizePos,(uint32_t)((b.size() - 4) - recSizePos)); // set size + b.template setAt(recSizePos,(uint32_t)(b.size() - (recSizePos + 4))); // set size } /** @@ -511,7 +511,7 @@ public: template static inline SharedPtr deserializeNew(const Identity &myIdentity,const Buffer &b,unsigned int &p) { - const uint32_t recSize = b.template at(p); p += 4; + const unsigned int recSize = b.template at(p); p += 4; if ((p + recSize) > b.size()) return SharedPtr(); // size invalid if (b.template at(p) != 1) @@ -540,7 +540,7 @@ public: np->_vRevision = b.template at(p); p += 2; np->_latency = b.template at(p); p += 4; - const unsigned int numPaths = b.template at(p); p += 4; + const unsigned int numPaths = b.template at(p); p += 2; for(unsigned int i=0;i_paths[np->_numPaths++].deserialize(b,p); diff --git a/node/Topology.cpp b/node/Topology.cpp index a3558558..6e8467c1 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -47,31 +47,20 @@ Topology::Topology(const RuntimeEnvironment *renv) : 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 p(Peer::deserializeNew(RR->identity,Buffer(all + ptr,reclen),pos)); - if (pos != reclen) - break; + SharedPtr p(Peer::deserializeNew(RR->identity,Buffer(all + ptr,reclen + 4),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[p->address()] = p; } catch ( ... ) { break; // stop if invalid records } -- cgit v1.2.3 From 781f06ef82033cdf2488f80266b3f7a8497eba69 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 16 Oct 2015 10:48:38 -0700 Subject: Accept OK for confirm of HELLO or ECHO. --- node/Peer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/node/Peer.cpp b/node/Peer.cpp index 8c5c5783..76b1d537 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -101,9 +101,9 @@ void Peer::received( } if (!pathIsConfirmed) { - if ((verb == Packet::VERB_OK)&&(inReVerb == Packet::VERB_HELLO)) { + if ((verb == Packet::VERB_OK)&&((inReVerb == Packet::VERB_HELLO)||(inReVerb == Packet::VERB_ECHO))) { - // Learn paths if they've been confirmed via a HELLO + // Learn paths if they've been confirmed via a HELLO or an ECHO RemotePath *slot = (RemotePath *)0; if (np < ZT_MAX_PEER_NETWORK_PATHS) { // Add new path -- cgit v1.2.3 From cc4d0199e7aa56d08e91dd9e21bbaba318afa8a4 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 16 Oct 2015 10:58:59 -0700 Subject: Fix vProto init. --- node/Peer.cpp | 1 + node/Peer.hpp | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/node/Peer.cpp b/node/Peer.cpp index 76b1d537..fdc8dca7 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -55,6 +55,7 @@ Peer::Peer(const Identity &myIdentity,const Identity &peerIdentity) _lastDirectPathPushSent(0), _lastDirectPathPushReceived(0), _lastPathSort(0), + _vProto(0), _vMajor(0), _vMinor(0), _vRevision(0), diff --git a/node/Peer.hpp b/node/Peer.hpp index 7e7e7f46..0aca70b4 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -330,7 +330,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; -- cgit v1.2.3 From 738fa5a5e5fc99512465032aec5916867f70e86b Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 16 Oct 2015 12:10:57 -0700 Subject: . --- node/Cluster.hpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/node/Cluster.hpp b/node/Cluster.hpp index 13d9e2f5..01db3641 100644 --- a/node/Cluster.hpp +++ b/node/Cluster.hpp @@ -61,6 +61,11 @@ */ #define ZT_CLUSTER_MEMBER_MAX_PHYSICAL_ADDRS 8 +/** + * How frequently should doPeriodicTasks() be ideally called? (ms) + */ +#define ZT_CLUSTER_PERIODIC_TASK_DEADLINE 10 + namespace ZeroTier { class RuntimeEnvironment; @@ -238,7 +243,7 @@ public: void replicateCertificateOfNetworkMembership(const CertificateOfMembership &com); /** - * This should be called no less frequently than once every 10 seconds. + * Call every ~ZT_CLUSTER_PERIODIC_TASK_DEADLINE milliseconds. */ void doPeriodicTasks(); -- cgit v1.2.3 From 0c43d34ce3294ca581f8918904c035e9d57aa72d Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 19 Oct 2015 10:00:35 -0700 Subject: World test stuff... some of this will be yanked before release. --- world/README.md | 4 +- world/alice-test/build.sh | 1 + world/alice-test/mkworld.cpp | 180 +++++++++++++++++++++++++++++++++++++++++++ world/build.sh | 1 + world/mkworld.cpp | 12 +-- 5 files changed, 189 insertions(+), 9 deletions(-) create mode 100755 world/alice-test/build.sh create mode 100644 world/alice-test/mkworld.cpp create mode 100755 world/build.sh diff --git a/world/README.md b/world/README.md index fbd8a0ae..dda4920a 100644 --- a/world/README.md +++ b/world/README.md @@ -3,7 +3,5 @@ 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: - - c++ -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 +See mkworld.cpp for documentation. To build from this directory use 'source ./build.sh'. diff --git a/world/alice-test/build.sh b/world/alice-test/build.sh new file mode 100755 index 00000000..58f21211 --- /dev/null +++ b/world/alice-test/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/alice-test/mkworld.cpp b/world/alice-test/mkworld.cpp new file mode 100644 index 00000000..42f3ab72 --- /dev/null +++ b/world/alice-test/mkworld.cpp @@ -0,0 +1,180 @@ +/* + * 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 . + * + * -- + * + * 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 +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +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 &roots,const C25519::Pair &signWith) + { + WorldMaker w; + w._id = id; + w._ts = ts; + w._updateSigningKey = sk; + w._roots = roots; + + Buffer 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, current.c25519"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 roots; + +#if 0 + // Old pre-October-2015 root server infrastructure with four independent single node roots -- it served us well! + // old US-SFO + roots.push_back(World::Root()); + roots.back().identity = Identity("7e19876aba:0:2a6e2b2318930f60eb097f70d0f4b028b2cd6d3d0c63c014b9039ff35390e41181f216fb2e6fa8d95c1ee9667156411905c3dccfea78d8c6dfafba688170b3fa"); + roots.back().stableEndpoints.push_back(InetAddress("198.199.97.220/9993")); + std::sort(roots.back().stableEndpoints.begin(),roots.back().stableEndpoints.end()); + // old EU-PARIS + roots.push_back(World::Root()); + roots.back().identity = Identity("8841408a2e:0:bb1d31f2c323e264e9e64172c1a74f77899555ed10751cd56e86405cde118d02dffe555d462ccf6a85b5631c12350c8d5dc409ba10b9025d0f445cf449d92b1c"); + roots.back().stableEndpoints.push_back(InetAddress("107.191.46.210/9993")); + std::sort(roots.back().stableEndpoints.begin(),roots.back().stableEndpoints.end()); + // old US-NYC + roots.push_back(World::Root()); + roots.back().identity = Identity("8acf059fe3:0:482f6ee5dfe902319b419de5bdc765209c0ecda38c4d6e4fcf0d33658398b4527dcd22f93112fb9befd02fd78bf7261b333fc105d192a623ca9e50fc60b374a5"); + roots.back().stableEndpoints.push_back(InetAddress("162.243.77.111/9993")); + std::sort(roots.back().stableEndpoints.begin(),roots.back().stableEndpoints.end()); + // old AP-SNG + roots.push_back(World::Root()); + roots.back().identity = Identity("9d219039f3:0:01f0922a98e3b34ebcbff333269dc265d7a020aab69d72be4d4acc9c8c9294785771256cd1d942a90d1bd1d2dca3ea84ef7d85afe6611fb43ff0b74126d90a6e"); + roots.back().stableEndpoints.push_back(InetAddress("128.199.197.217/9993")); + std::sort(roots.back().stableEndpoints.begin(),roots.back().stableEndpoints.end()); +#endif + + // ALICE TEST + roots.push_back(World::Root()); + roots.back().identity = Identity(""); + roots.back().stableEndpoints.push_back(InetAddress("169.57.143.104/9993")); + std::sort(roots.back().stableEndpoints.begin(),roots.back().stableEndpoints.end()); + + std::sort(roots.begin(),roots.end()); + + const uint64_t id = ZT_WORLD_ID_EARTH; + const uint64_t ts = OSUtils::now(); + + //////////////////////////////////////////////////////////////////////////// + // END WORLD SETUP --------------------------------------------------------- + //////////////////////////////////////////////////////////////////////////// + + 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 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; + } + fwrite(outtmp.data(),outtmp.size(),1,stdout); + fflush(stdout); + + fprintf(stderr,"INFO: wrote %u bytes to stdout"ZT_EOL_S,outtmp.size()); + + fprintf(stderr,ZT_EOL_S); + fprintf(stderr,"#define ZT_DEFAULT_WORLD_LENGTH %u"ZT_EOL_S,outtmp.size()); + fprintf(stderr,"static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {"); + for(unsigned int i=0;i 0) + fprintf(stderr,","); + fprintf(stderr,"0x%.2x",(unsigned int)d[i]); + } + fprintf(stderr,"};"ZT_EOL_S); + + return 0; +} 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/mkworld.cpp b/world/mkworld.cpp index 75230da4..fd7bb51f 100644 --- a/world/mkworld.cpp +++ b/world/mkworld.cpp @@ -50,12 +50,12 @@ #include #include -#include "../node/Constants.hpp" -#include "../node/World.hpp" -#include "../node/C25519.hpp" -#include "../node/Identity.hpp" -#include "../node/InetAddress.hpp" -#include "../osdep/OSUtils.hpp" +#include +#include +#include +#include +#include +#include using namespace ZeroTier; -- cgit v1.2.3 From aa6e3c79a0d5942b289a6efc68c61667ce4059a7 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 19 Oct 2015 10:49:31 -0700 Subject: Some test stuff that will not be pushed elsewhere. --- node/Topology.cpp | 8 ++++++-- world/alice-test/alice-test.bin | Bin 0 -> 257 bytes world/alice-test/alice-test.out | 5 +++++ world/alice-test/current.c25519 | 3 +++ world/alice-test/mkworld.cpp | 2 +- world/alice-test/previous.c25519 | 3 +++ 6 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 world/alice-test/alice-test.bin create mode 100644 world/alice-test/alice-test.out create mode 100644 world/alice-test/current.c25519 create mode 100644 world/alice-test/previous.c25519 diff --git a/node/Topology.cpp b/node/Topology.cpp index 6e8467c1..e36a0609 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -34,8 +34,12 @@ namespace ZeroTier { // Default World -#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,0x4f,0xdf,0xbf,0xfc,0xbb,0x6c,0x7e,0x15,0x67,0x85,0x1b,0xb4,0x65,0x04,0x01,0xaf,0x56,0xbf,0xe7,0x63,0x9d,0x77,0xef,0xa4,0x1e,0x61,0x53,0x88,0xcb,0x8d,0x78,0xe5,0x47,0x38,0x98,0x5a,0x6c,0x8a,0xdd,0xe6,0x9c,0x65,0xdf,0x1a,0x80,0x63,0xce,0x2e,0x4d,0x48,0x24,0x3d,0x68,0x87,0x96,0x13,0x89,0xba,0x25,0x6f,0xc9,0xb0,0x9f,0x20,0xc5,0x4c,0x51,0x7b,0x30,0xb7,0x5f,0xba,0xca,0xa4,0xc5,0x48,0xa3,0x15,0xab,0x2f,0x1d,0x64,0xe8,0x04,0x42,0xb3,0x1c,0x51,0x8b,0x2a,0x04,0x01,0xf8,0xe1,0x81,0xaf,0x60,0x2f,0x70,0x3e,0xcd,0x0b,0x21,0x38,0x19,0x62,0x02,0xbd,0x0e,0x33,0x1d,0x0a,0x7b,0xf1,0xec,0xad,0xef,0x54,0xb3,0x7b,0x17,0x84,0xaa,0xda,0x0a,0x85,0x5d,0x0b,0x1c,0x05,0x83,0xb9,0x0e,0x3e,0xe3,0xb4,0xd1,0x8b,0x5b,0x64,0xf7,0xcf,0xe1,0xff,0x5d,0xc2,0x2a,0xcf,0x60,0x7b,0x09,0xb4,0xa3,0x86,0x3c,0x5a,0x7e,0x31,0xa0,0xc7,0xb4,0x86,0xe3,0x41,0x33,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}; +//#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,0x4f,0xdf,0xbf,0xfc,0xbb,0x6c,0x7e,0x15,0x67,0x85,0x1b,0xb4,0x65,0x04,0x01,0xaf,0x56,0xbf,0xe7,0x63,0x9d,0x77,0xef,0xa4,0x1e,0x61,0x53,0x88,0xcb,0x8d,0x78,0xe5,0x47,0x38,0x98,0x5a,0x6c,0x8a,0xdd,0xe6,0x9c,0x65,0xdf,0x1a,0x80,0x63,0xce,0x2e,0x4d,0x48,0x24,0x3d,0x68,0x87,0x96,0x13,0x89,0xba,0x25,0x6f,0xc9,0xb0,0x9f,0x20,0xc5,0x4c,0x51,0x7b,0x30,0xb7,0x5f,0xba,0xca,0xa4,0xc5,0x48,0xa3,0x15,0xab,0x2f,0x1d,0x64,0xe8,0x04,0x42,0xb3,0x1c,0x51,0x8b,0x2a,0x04,0x01,0xf8,0xe1,0x81,0xaf,0x60,0x2f,0x70,0x3e,0xcd,0x0b,0x21,0x38,0x19,0x62,0x02,0xbd,0x0e,0x33,0x1d,0x0a,0x7b,0xf1,0xec,0xad,0xef,0x54,0xb3,0x7b,0x17,0x84,0xaa,0xda,0x0a,0x85,0x5d,0x0b,0x1c,0x05,0x83,0xb9,0x0e,0x3e,0xe3,0xb4,0xd1,0x8b,0x5b,0x64,0xf7,0xcf,0xe1,0xff,0x5d,0xc2,0x2a,0xcf,0x60,0x7b,0x09,0xb4,0xa3,0x86,0x3c,0x5a,0x7e,0x31,0xa0,0xc7,0xb4,0x86,0xe3,0x41,0x33,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}; + +// ALICE-TEST +#define ZT_DEFAULT_WORLD_LENGTH 257 +static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {0x01,0x00,0x00,0x00,0x00,0x08,0xea,0xc9,0x0a,0x00,0x00,0x01,0x50,0x81,0x2a,0x54,0x6f,0x72,0xb0,0x3b,0xbe,0x73,0xda,0xbd,0xfb,0x85,0x77,0x9f,0xc9,0x2e,0x17,0xc8,0x11,0x6e,0xda,0x61,0x80,0xd1,0x41,0xcb,0x7c,0x2d,0x2b,0xa4,0x34,0x75,0x19,0x64,0x20,0x80,0x0a,0x22,0x32,0xf2,0x01,0x6c,0xfe,0x79,0xa6,0x7d,0xec,0x10,0x7e,0x03,0xf3,0xa2,0xa0,0x19,0xc8,0x7c,0xfd,0x6c,0x56,0x52,0xa8,0xfb,0xdc,0xfb,0x93,0x81,0x3e,0x63,0x8b,0xb3,0xb6,0x72,0x45,0xa9,0x81,0x81,0xcc,0xea,0x7f,0x2f,0xd9,0x59,0xce,0xc8,0x51,0x12,0xc3,0xe3,0x44,0x76,0x54,0xed,0xe7,0x8d,0x34,0x0b,0x5d,0x10,0x3d,0x52,0x04,0x9b,0xe1,0xb2,0x36,0x51,0x75,0x14,0x30,0x53,0xe8,0x4b,0xe4,0x91,0x9a,0xed,0x99,0x56,0xa3,0x8d,0x5e,0x14,0xff,0x66,0xd8,0x4f,0xf7,0x3c,0x23,0xbe,0x02,0xbb,0x1e,0xb6,0x7e,0x07,0xfa,0x7c,0x7e,0x50,0xe8,0x40,0xf9,0x37,0x70,0x1a,0x75,0xcf,0x19,0xe6,0x83,0xe1,0x5c,0x20,0x1d,0x1e,0x5b,0xe5,0x6a,0xbe,0xe7,0xab,0xec,0x01,0xd6,0xdd,0xca,0x6a,0xb5,0x00,0x4e,0x76,0x12,0x07,0xd8,0xb4,0x20,0x0b,0xe4,0x4f,0x47,0x8e,0x3d,0xa1,0x48,0xc1,0x60,0x99,0x11,0x0e,0xe7,0x1b,0x64,0x58,0x6d,0xda,0x11,0x8e,0x40,0x22,0xab,0x63,0x68,0x2c,0xe1,0x37,0xda,0x8b,0xa8,0x17,0xfc,0x7f,0x73,0xaa,0x31,0x63,0xf2,0xe3,0x33,0x93,0x3e,0x29,0x94,0xc4,0x6b,0x4f,0x41,0x19,0x30,0x7b,0xe8,0x85,0x5a,0x72,0x00,0x01,0x04,0xa9,0x39,0x8f,0x68,0x27,0x09}; Topology::Topology(const RuntimeEnvironment *renv) : RR(renv), diff --git a/world/alice-test/alice-test.bin b/world/alice-test/alice-test.bin new file mode 100644 index 00000000..2fdaf7b3 Binary files /dev/null and b/world/alice-test/alice-test.bin differ diff --git a/world/alice-test/alice-test.out b/world/alice-test/alice-test.out new file mode 100644 index 00000000..20077bf2 --- /dev/null +++ b/world/alice-test/alice-test.out @@ -0,0 +1,5 @@ +INFO: generating and signing id==149604618 ts==1445276046447 +INFO: wrote 257 bytes to stdout + +#define ZT_DEFAULT_WORLD_LENGTH 257 +static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {0x01,0x00,0x00,0x00,0x00,0x08,0xea,0xc9,0x0a,0x00,0x00,0x01,0x50,0x81,0x2a,0x54,0x6f,0x72,0xb0,0x3b,0xbe,0x73,0xda,0xbd,0xfb,0x85,0x77,0x9f,0xc9,0x2e,0x17,0xc8,0x11,0x6e,0xda,0x61,0x80,0xd1,0x41,0xcb,0x7c,0x2d,0x2b,0xa4,0x34,0x75,0x19,0x64,0x20,0x80,0x0a,0x22,0x32,0xf2,0x01,0x6c,0xfe,0x79,0xa6,0x7d,0xec,0x10,0x7e,0x03,0xf3,0xa2,0xa0,0x19,0xc8,0x7c,0xfd,0x6c,0x56,0x52,0xa8,0xfb,0xdc,0xfb,0x93,0x81,0x3e,0x63,0x8b,0xb3,0xb6,0x72,0x45,0xa9,0x81,0x81,0xcc,0xea,0x7f,0x2f,0xd9,0x59,0xce,0xc8,0x51,0x12,0xc3,0xe3,0x44,0x76,0x54,0xed,0xe7,0x8d,0x34,0x0b,0x5d,0x10,0x3d,0x52,0x04,0x9b,0xe1,0xb2,0x36,0x51,0x75,0x14,0x30,0x53,0xe8,0x4b,0xe4,0x91,0x9a,0xed,0x99,0x56,0xa3,0x8d,0x5e,0x14,0xff,0x66,0xd8,0x4f,0xf7,0x3c,0x23,0xbe,0x02,0xbb,0x1e,0xb6,0x7e,0x07,0xfa,0x7c,0x7e,0x50,0xe8,0x40,0xf9,0x37,0x70,0x1a,0x75,0xcf,0x19,0xe6,0x83,0xe1,0x5c,0x20,0x1d,0x1e,0x5b,0xe5,0x6a,0xbe,0xe7,0xab,0xec,0x01,0xd6,0xdd,0xca,0x6a,0xb5,0x00,0x4e,0x76,0x12,0x07,0xd8,0xb4,0x20,0x0b,0xe4,0x4f,0x47,0x8e,0x3d,0xa1,0x48,0xc1,0x60,0x99,0x11,0x0e,0xe7,0x1b,0x64,0x58,0x6d,0xda,0x11,0x8e,0x40,0x22,0xab,0x63,0x68,0x2c,0xe1,0x37,0xda,0x8b,0xa8,0x17,0xfc,0x7f,0x73,0xaa,0x31,0x63,0xf2,0xe3,0x33,0x93,0x3e,0x29,0x94,0xc4,0x6b,0x4f,0x41,0x19,0x30,0x7b,0xe8,0x85,0x5a,0x72,0x00,0x01,0x04,0xa9,0x39,0x8f,0x68,0x27,0x09}; diff --git a/world/alice-test/current.c25519 b/world/alice-test/current.c25519 new file mode 100644 index 00000000..a3e6d596 --- /dev/null +++ b/world/alice-test/current.c25519 @@ -0,0 +1,3 @@ +r;sڽw.naA|-+4ud +"2ly}~|lVR>H6_oF@`5+\&t<2 +ţ֊jn(fJÁ紮U)$o \ No newline at end of file diff --git a/world/alice-test/mkworld.cpp b/world/alice-test/mkworld.cpp index 42f3ab72..e680b97e 100644 --- a/world/alice-test/mkworld.cpp +++ b/world/alice-test/mkworld.cpp @@ -135,7 +135,7 @@ int main(int argc,char **argv) // ALICE TEST roots.push_back(World::Root()); - roots.back().identity = Identity(""); + roots.back().identity = Identity("d6ddca6ab5:0:4e761207d8b4200be44f478e3da148c16099110ee71b64586dda118e4022ab63682ce137da8ba817fc7f73aa3163f2e333933e2994c46b4f4119307be8855a72"); roots.back().stableEndpoints.push_back(InetAddress("169.57.143.104/9993")); std::sort(roots.back().stableEndpoints.begin(),roots.back().stableEndpoints.end()); diff --git a/world/alice-test/previous.c25519 b/world/alice-test/previous.c25519 new file mode 100644 index 00000000..a3e6d596 --- /dev/null +++ b/world/alice-test/previous.c25519 @@ -0,0 +1,3 @@ +r;sڽw.naA|-+4ud +"2ly}~|lVR>H6_oF@`5+\&t<2 +ţ֊jn(fJÁ紮U)$o \ No newline at end of file -- cgit v1.2.3 From 95953b48f963213a803b230e2d83416257716e65 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 19 Oct 2015 12:56:29 -0700 Subject: Do not allow VERB_RENDEZVOUS from non-upstream peers to block potential DOS vector. --- node/IncomingPacket.cpp | 29 +++++++++++++++++------------ node/Topology.cpp | 19 +++++++++++++++++++ node/Topology.hpp | 15 +++++++-------- 3 files changed, 43 insertions(+), 20 deletions(-) diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 4386e370..6b39963a 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -461,21 +461,26 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr &peer) { try { - const Address with(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); - const SharedPtr withPeer(RR->topology->getPeer(with)); - if (withPeer) { - const unsigned int port = at(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 withPeer(RR->topology->getPeer(with)); + if (withPeer) { + const unsigned int port = at(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 ( ... ) { TRACE("dropped RENDEZVOUS from %s(%s): unexpected exception",peer->address().toString().c_str(),_remoteAddress.toString().c_str()); diff --git a/node/Topology.cpp b/node/Topology.cpp index e36a0609..dc21b243 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -29,6 +29,8 @@ #include "Topology.hpp" #include "RuntimeEnvironment.hpp" #include "Node.hpp" +#include "Network.hpp" +#include "NetworkConfig.hpp" #include "Buffer.hpp" namespace ZeroTier { @@ -283,6 +285,23 @@ keep_searching_for_roots: return bestRoot; } +bool Topology::isUpstream(const Identity &id) const +{ + if (isRoot(id)) + return true; + std::vector< SharedPtr > nws(RR->node->allNetworks()); + for(std::vector< SharedPtr >::const_iterator nw(nws.begin());nw!=nws.end();++nw) { + SharedPtr nc((*nw)->config2()); + if (nc) { + for(std::vector< std::pair >::const_iterator r(nc->relays().begin());r!=nc->relays().end();++r) { + if (r->first == id.address()) + return true; + } + } + } + return false; +} + bool Topology::worldUpdateIfValid(const World &newWorld) { Mutex::Lock _l(_lock); diff --git a/node/Topology.hpp b/node/Topology.hpp index 9e9ccc01..48e264a8 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -136,16 +136,15 @@ public: inline bool isRoot(const Identity &id) const { Mutex::Lock _l(_lock); - if (std::find(_rootAddresses.begin(),_rootAddresses.end(),id.address()) != _rootAddresses.end()) { - // Double check full identity for security reasons - for(std::vector::const_iterator r(_world.roots().begin());r!=_world.roots().end();++r) { - if (id == r->identity) - return true; - } - } - return false; + 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 */ -- cgit v1.2.3 From 3adb183c5f76b69013d052383c4b812e3947041e Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 19 Oct 2015 13:38:27 -0700 Subject: Fix bad COM attachment bug and eliminate an unnecessary redundant check. --- node/IncomingPacket.cpp | 6 ++---- node/Switch.cpp | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 6b39963a..19747bbd 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -529,15 +529,13 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

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; diff --git a/node/Switch.cpp b/node/Switch.cpp index 9ea8ac49..249a21d5 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -203,7 +203,7 @@ void Switch::onLocalEthernet(const SharedPtr &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 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 +271,7 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c SharedPtr 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 { -- cgit v1.2.3 From 584072fa6a86b7cca0a708d7dd4c302aa444f2b6 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 19 Oct 2015 14:04:36 -0700 Subject: Fix for V4/V6 stable addressing. --- node/Node.cpp | 32 ++++++++++++++++++++++++++------ node/Peer.cpp | 1 + 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/node/Node.cpp b/node/Node.cpp index 5aa4b7d3..26d5513e 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -197,10 +197,11 @@ public: if (!stableEndpoint4) { if (addr.ss_family == AF_INET) stableEndpoint4 = addr; - } else if (!stableEndpoint6) { + } + if (!stableEndpoint6) { if (addr.ss_family == AF_INET6) stableEndpoint6 = addr; - } else break; // have both! + } } break; } @@ -223,10 +224,29 @@ public: 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. - if ((!p->doPingAndKeepalive(RR,_now,AF_INET))&&(stableEndpoint4)) - p->attemptToContactAt(RR,InetAddress(),stableEndpoint4,_now); - if ((!p->doPingAndKeepalive(RR,_now,AF_INET6))&&(stableEndpoint6)) - p->attemptToContactAt(RR,InetAddress(),stableEndpoint6,_now); + bool needToContactIndirect = true; + if (!p->doPingAndKeepalive(RR,_now,AF_INET)) { + if (stableEndpoint4) { + needToContactIndirect = false; + p->attemptToContactAt(RR,InetAddress(),stableEndpoint4,_now); + } + } else needToContactIndirect = false; + if (!p->doPingAndKeepalive(RR,_now,AF_INET6)) { + if (stableEndpoint6) { + needToContactIndirect = false; + p->attemptToContactAt(RR,InetAddress(),stableEndpoint6,_now); + } + } else needToContactIndirect = false; + + 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->alive(_now)) { // Normal nodes get their preferred link kept alive if the node has generated frame traffic recently diff --git a/node/Peer.cpp b/node/Peer.cpp index fdc8dca7..a9d2f671 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -205,6 +205,7 @@ bool Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now,int inet } return true; } + return false; } -- cgit v1.2.3 From 50f3ccd3c9630dfc0169973573f5b3729524441c Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 19 Oct 2015 15:03:58 -0700 Subject: . --- node/Peer.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/node/Peer.cpp b/node/Peer.cpp index a9d2f671..e0408156 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -202,6 +202,8 @@ bool Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now,int inet _natKeepaliveBuf += (uint32_t)((now * 0x9e3779b1) >> 1); // tumble this around to send constantly varying (meaningless) payloads RR->node->putPacket(p->localAddress(),p->address(),&_natKeepaliveBuf,sizeof(_natKeepaliveBuf)); p->sent(now); + } else { + TRACE("no PING or NAT keepalive: %llums/%llums send/receive inactivity",now - p->lastSend(),now - p->lastReceived()) } return true; } -- cgit v1.2.3 From 915077875759f1040b8bba281ef3d4f82e4ac1ab Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 19 Oct 2015 15:04:26 -0700 Subject: . --- node/Peer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/Peer.cpp b/node/Peer.cpp index e0408156..ba6ef4af 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -203,7 +203,7 @@ bool Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now,int inet RR->node->putPacket(p->localAddress(),p->address(),&_natKeepaliveBuf,sizeof(_natKeepaliveBuf)); p->sent(now); } else { - TRACE("no PING or NAT keepalive: %llums/%llums send/receive inactivity",now - p->lastSend(),now - p->lastReceived()) + TRACE("no PING or NAT keepalive: %llums/%llums send/receive inactivity",now - p->lastSend(),now - p->lastReceived()); } return true; } -- cgit v1.2.3 From 0b2e5ed499aea0076caa2dc1d8784796e54da538 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 19 Oct 2015 15:11:43 -0700 Subject: Fix some broken logic in Path::reliable() --- node/Path.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/node/Path.hpp b/node/Path.hpp index 6a69e071..6fa3c52e 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -114,7 +114,9 @@ public: */ 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; } /** -- cgit v1.2.3 From cfdcce6d1299b4bc407b9b44c0abb55c5ea9f4b5 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 19 Oct 2015 15:19:04 -0700 Subject: Fix very obscure IP scope classification logic bug. --- node/InetAddress.cpp | 12 +++++------- node/Peer.cpp | 2 +- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/node/InetAddress.cpp b/node/InetAddress.cpp index e542f0d4..abb46240 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: { diff --git a/node/Peer.cpp b/node/Peer.cpp index ba6ef4af..6f566be4 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -203,7 +203,7 @@ bool Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now,int inet RR->node->putPacket(p->localAddress(),p->address(),&_natKeepaliveBuf,sizeof(_natKeepaliveBuf)); p->sent(now); } else { - TRACE("no PING or NAT keepalive: %llums/%llums send/receive inactivity",now - p->lastSend(),now - p->lastReceived()); + 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; } -- cgit v1.2.3 From 69dad37d8f6fdc1ca57077b1fecdc64b23254588 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 19 Oct 2015 15:23:43 -0700 Subject: Restore default World for commit to upstream --- node/Topology.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/node/Topology.cpp b/node/Topology.cpp index dc21b243..56ca47c8 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -36,12 +36,12 @@ namespace ZeroTier { // Default World -//#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,0x4f,0xdf,0xbf,0xfc,0xbb,0x6c,0x7e,0x15,0x67,0x85,0x1b,0xb4,0x65,0x04,0x01,0xaf,0x56,0xbf,0xe7,0x63,0x9d,0x77,0xef,0xa4,0x1e,0x61,0x53,0x88,0xcb,0x8d,0x78,0xe5,0x47,0x38,0x98,0x5a,0x6c,0x8a,0xdd,0xe6,0x9c,0x65,0xdf,0x1a,0x80,0x63,0xce,0x2e,0x4d,0x48,0x24,0x3d,0x68,0x87,0x96,0x13,0x89,0xba,0x25,0x6f,0xc9,0xb0,0x9f,0x20,0xc5,0x4c,0x51,0x7b,0x30,0xb7,0x5f,0xba,0xca,0xa4,0xc5,0x48,0xa3,0x15,0xab,0x2f,0x1d,0x64,0xe8,0x04,0x42,0xb3,0x1c,0x51,0x8b,0x2a,0x04,0x01,0xf8,0xe1,0x81,0xaf,0x60,0x2f,0x70,0x3e,0xcd,0x0b,0x21,0x38,0x19,0x62,0x02,0xbd,0x0e,0x33,0x1d,0x0a,0x7b,0xf1,0xec,0xad,0xef,0x54,0xb3,0x7b,0x17,0x84,0xaa,0xda,0x0a,0x85,0x5d,0x0b,0x1c,0x05,0x83,0xb9,0x0e,0x3e,0xe3,0xb4,0xd1,0x8b,0x5b,0x64,0xf7,0xcf,0xe1,0xff,0x5d,0xc2,0x2a,0xcf,0x60,0x7b,0x09,0xb4,0xa3,0x86,0x3c,0x5a,0x7e,0x31,0xa0,0xc7,0xb4,0x86,0xe3,0x41,0x33,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}; +#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,0x4f,0xdf,0xbf,0xfc,0xbb,0x6c,0x7e,0x15,0x67,0x85,0x1b,0xb4,0x65,0x04,0x01,0xaf,0x56,0xbf,0xe7,0x63,0x9d,0x77,0xef,0xa4,0x1e,0x61,0x53,0x88,0xcb,0x8d,0x78,0xe5,0x47,0x38,0x98,0x5a,0x6c,0x8a,0xdd,0xe6,0x9c,0x65,0xdf,0x1a,0x80,0x63,0xce,0x2e,0x4d,0x48,0x24,0x3d,0x68,0x87,0x96,0x13,0x89,0xba,0x25,0x6f,0xc9,0xb0,0x9f,0x20,0xc5,0x4c,0x51,0x7b,0x30,0xb7,0x5f,0xba,0xca,0xa4,0xc5,0x48,0xa3,0x15,0xab,0x2f,0x1d,0x64,0xe8,0x04,0x42,0xb3,0x1c,0x51,0x8b,0x2a,0x04,0x01,0xf8,0xe1,0x81,0xaf,0x60,0x2f,0x70,0x3e,0xcd,0x0b,0x21,0x38,0x19,0x62,0x02,0xbd,0x0e,0x33,0x1d,0x0a,0x7b,0xf1,0xec,0xad,0xef,0x54,0xb3,0x7b,0x17,0x84,0xaa,0xda,0x0a,0x85,0x5d,0x0b,0x1c,0x05,0x83,0xb9,0x0e,0x3e,0xe3,0xb4,0xd1,0x8b,0x5b,0x64,0xf7,0xcf,0xe1,0xff,0x5d,0xc2,0x2a,0xcf,0x60,0x7b,0x09,0xb4,0xa3,0x86,0x3c,0x5a,0x7e,0x31,0xa0,0xc7,0xb4,0x86,0xe3,0x41,0x33,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}; // ALICE-TEST -#define ZT_DEFAULT_WORLD_LENGTH 257 -static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {0x01,0x00,0x00,0x00,0x00,0x08,0xea,0xc9,0x0a,0x00,0x00,0x01,0x50,0x81,0x2a,0x54,0x6f,0x72,0xb0,0x3b,0xbe,0x73,0xda,0xbd,0xfb,0x85,0x77,0x9f,0xc9,0x2e,0x17,0xc8,0x11,0x6e,0xda,0x61,0x80,0xd1,0x41,0xcb,0x7c,0x2d,0x2b,0xa4,0x34,0x75,0x19,0x64,0x20,0x80,0x0a,0x22,0x32,0xf2,0x01,0x6c,0xfe,0x79,0xa6,0x7d,0xec,0x10,0x7e,0x03,0xf3,0xa2,0xa0,0x19,0xc8,0x7c,0xfd,0x6c,0x56,0x52,0xa8,0xfb,0xdc,0xfb,0x93,0x81,0x3e,0x63,0x8b,0xb3,0xb6,0x72,0x45,0xa9,0x81,0x81,0xcc,0xea,0x7f,0x2f,0xd9,0x59,0xce,0xc8,0x51,0x12,0xc3,0xe3,0x44,0x76,0x54,0xed,0xe7,0x8d,0x34,0x0b,0x5d,0x10,0x3d,0x52,0x04,0x9b,0xe1,0xb2,0x36,0x51,0x75,0x14,0x30,0x53,0xe8,0x4b,0xe4,0x91,0x9a,0xed,0x99,0x56,0xa3,0x8d,0x5e,0x14,0xff,0x66,0xd8,0x4f,0xf7,0x3c,0x23,0xbe,0x02,0xbb,0x1e,0xb6,0x7e,0x07,0xfa,0x7c,0x7e,0x50,0xe8,0x40,0xf9,0x37,0x70,0x1a,0x75,0xcf,0x19,0xe6,0x83,0xe1,0x5c,0x20,0x1d,0x1e,0x5b,0xe5,0x6a,0xbe,0xe7,0xab,0xec,0x01,0xd6,0xdd,0xca,0x6a,0xb5,0x00,0x4e,0x76,0x12,0x07,0xd8,0xb4,0x20,0x0b,0xe4,0x4f,0x47,0x8e,0x3d,0xa1,0x48,0xc1,0x60,0x99,0x11,0x0e,0xe7,0x1b,0x64,0x58,0x6d,0xda,0x11,0x8e,0x40,0x22,0xab,0x63,0x68,0x2c,0xe1,0x37,0xda,0x8b,0xa8,0x17,0xfc,0x7f,0x73,0xaa,0x31,0x63,0xf2,0xe3,0x33,0x93,0x3e,0x29,0x94,0xc4,0x6b,0x4f,0x41,0x19,0x30,0x7b,0xe8,0x85,0x5a,0x72,0x00,0x01,0x04,0xa9,0x39,0x8f,0x68,0x27,0x09}; +//#define ZT_DEFAULT_WORLD_LENGTH 257 +//static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {0x01,0x00,0x00,0x00,0x00,0x08,0xea,0xc9,0x0a,0x00,0x00,0x01,0x50,0x81,0x2a,0x54,0x6f,0x72,0xb0,0x3b,0xbe,0x73,0xda,0xbd,0xfb,0x85,0x77,0x9f,0xc9,0x2e,0x17,0xc8,0x11,0x6e,0xda,0x61,0x80,0xd1,0x41,0xcb,0x7c,0x2d,0x2b,0xa4,0x34,0x75,0x19,0x64,0x20,0x80,0x0a,0x22,0x32,0xf2,0x01,0x6c,0xfe,0x79,0xa6,0x7d,0xec,0x10,0x7e,0x03,0xf3,0xa2,0xa0,0x19,0xc8,0x7c,0xfd,0x6c,0x56,0x52,0xa8,0xfb,0xdc,0xfb,0x93,0x81,0x3e,0x63,0x8b,0xb3,0xb6,0x72,0x45,0xa9,0x81,0x81,0xcc,0xea,0x7f,0x2f,0xd9,0x59,0xce,0xc8,0x51,0x12,0xc3,0xe3,0x44,0x76,0x54,0xed,0xe7,0x8d,0x34,0x0b,0x5d,0x10,0x3d,0x52,0x04,0x9b,0xe1,0xb2,0x36,0x51,0x75,0x14,0x30,0x53,0xe8,0x4b,0xe4,0x91,0x9a,0xed,0x99,0x56,0xa3,0x8d,0x5e,0x14,0xff,0x66,0xd8,0x4f,0xf7,0x3c,0x23,0xbe,0x02,0xbb,0x1e,0xb6,0x7e,0x07,0xfa,0x7c,0x7e,0x50,0xe8,0x40,0xf9,0x37,0x70,0x1a,0x75,0xcf,0x19,0xe6,0x83,0xe1,0x5c,0x20,0x1d,0x1e,0x5b,0xe5,0x6a,0xbe,0xe7,0xab,0xec,0x01,0xd6,0xdd,0xca,0x6a,0xb5,0x00,0x4e,0x76,0x12,0x07,0xd8,0xb4,0x20,0x0b,0xe4,0x4f,0x47,0x8e,0x3d,0xa1,0x48,0xc1,0x60,0x99,0x11,0x0e,0xe7,0x1b,0x64,0x58,0x6d,0xda,0x11,0x8e,0x40,0x22,0xab,0x63,0x68,0x2c,0xe1,0x37,0xda,0x8b,0xa8,0x17,0xfc,0x7f,0x73,0xaa,0x31,0x63,0xf2,0xe3,0x33,0x93,0x3e,0x29,0x94,0xc4,0x6b,0x4f,0x41,0x19,0x30,0x7b,0xe8,0x85,0x5a,0x72,0x00,0x01,0x04,0xa9,0x39,0x8f,0x68,0x27,0x09}; Topology::Topology(const RuntimeEnvironment *renv) : RR(renv), -- cgit v1.2.3 From 5e6eae620bec49086e2ad80c119f3386d84092b1 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 19 Oct 2015 16:18:57 -0700 Subject: Make _members dynamically allocated due to static array limit on ARM. --- node/Cluster.cpp | 4 +++- node/Cluster.hpp | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/node/Cluster.cpp b/node/Cluster.cpp index c08bf002..bfa39d22 100644 --- a/node/Cluster.cpp +++ b/node/Cluster.cpp @@ -56,7 +56,8 @@ Cluster::Cluster(const RuntimeEnvironment *renv,uint16_t id,DistanceAlgorithm da _y(y), _z(z), _da(da), - _id(id) + _id(id), + _members(new _Member[65536]) { uint16_t stmp[ZT_SHA512_DIGEST_LEN / sizeof(uint16_t)]; @@ -76,6 +77,7 @@ Cluster::~Cluster() { Utils::burn(_masterSecret,sizeof(_masterSecret)); Utils::burn(_key,sizeof(_key)); + delete [] _members; } void Cluster::handleIncomingStateMessage(const void *msg,unsigned int len) diff --git a/node/Cluster.hpp b/node/Cluster.hpp index 01db3641..016730e3 100644 --- a/node/Cluster.hpp +++ b/node/Cluster.hpp @@ -303,7 +303,7 @@ private: ~_Member() { Utils::burn(key,sizeof(key)); } }; - _Member _members[65536]; // cluster IDs can be from 0 to 65535 (16-bit) + _Member *const _members; // cluster IDs can be from 0 to 65535 (16-bit) std::vector _memberIds; Mutex _memberIds_m; -- cgit v1.2.3 From 6040574d8d9263ac50a607d12195c44c3746f47b Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Mon, 19 Oct 2015 20:20:42 -0700 Subject: set up project and base UI for a native windows UI for ZeroTier --- .gitignore | 2 + windows/WinUI/App.config | 6 ++ windows/WinUI/App.xaml | 8 ++ windows/WinUI/App.xaml.cs | 17 ++++ windows/WinUI/MainWindow.xaml | 95 ++++++++++++++++++++ windows/WinUI/MainWindow.xaml.cs | 28 ++++++ windows/WinUI/Properties/AssemblyInfo.cs | 55 ++++++++++++ windows/WinUI/Properties/Resources.Designer.cs | 71 +++++++++++++++ windows/WinUI/Properties/Resources.resx | 117 +++++++++++++++++++++++++ windows/WinUI/Properties/Settings.Designer.cs | 30 +++++++ windows/WinUI/Properties/Settings.settings | 7 ++ windows/WinUI/Themes/Generic.xaml | 7 ++ windows/WinUI/WinUI.csproj | 111 +++++++++++++++++++++++ windows/ZeroTierOne.sln | 79 +++++++++++++++++ 14 files changed, 633 insertions(+) create mode 100644 windows/WinUI/App.config create mode 100644 windows/WinUI/App.xaml create mode 100644 windows/WinUI/App.xaml.cs create mode 100644 windows/WinUI/MainWindow.xaml create mode 100644 windows/WinUI/MainWindow.xaml.cs create mode 100644 windows/WinUI/Properties/AssemblyInfo.cs create mode 100644 windows/WinUI/Properties/Resources.Designer.cs create mode 100644 windows/WinUI/Properties/Resources.resx create mode 100644 windows/WinUI/Properties/Settings.Designer.cs create mode 100644 windows/WinUI/Properties/Settings.settings create mode 100644 windows/WinUI/Themes/Generic.xaml create mode 100644 windows/WinUI/WinUI.csproj diff --git a/.gitignore b/.gitignore index 2dbec1e5..734f73bb 100755 --- a/.gitignore +++ b/.gitignore @@ -75,3 +75,5 @@ java/doc/ java/build_win64/ java/build_win32/ /java/mac32_64/ +windows/WinUI/obj/ +windows/WinUI/bin/ diff --git a/windows/WinUI/App.config b/windows/WinUI/App.config new file mode 100644 index 00000000..8e156463 --- /dev/null +++ b/windows/WinUI/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/windows/WinUI/App.xaml b/windows/WinUI/App.xaml new file mode 100644 index 00000000..3788901a --- /dev/null +++ b/windows/WinUI/App.xaml @@ -0,0 +1,8 @@ + + + + + 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 +{ + ///

+ /// Interaction logic for App.xaml + /// + public partial class App : Application + { + } +} diff --git a/windows/WinUI/MainWindow.xaml b/windows/WinUI/MainWindow.xaml new file mode 100644 index 00000000..c104dfb6 --- /dev/null +++ b/windows/WinUI/MainWindow.xaml @@ -0,0 +1,95 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - -
- { - (this.tabIndex === 1) ? ( -
-
-
Address
-
Version
-
Latency
-
Data Paths
-
Last Unicast
-
Last Multicast
-
Role
-
- { - this.state._peers.map(function(peer) { - return ( -
-
{peer['address']}
-
{(peer['version'] === '-1.-1.-1') ? '-' : peer['version']}
-
{peer['latency']}
-
- { - (peer['paths'].length === 0) ? ( -
- ) : ( -
- { - peer['paths'].map(function(path) { - var cn = ((path.active)||(path.fixed)) ? (path.preferred ? 'peerPathPreferred' : 'peerPathActive') : 'peerPathInactive'; - return ( -
{path.address}  {this.ago(path.lastSend)}/{this.ago(path.lastReceive)}
- ); - }.bind(this)) - } -
- ) - } -
-
{this.ago(peer['lastUnicastFrame'])}
-
{this.ago(peer['lastMulticastFrame'])}
-
{peer['role']}
-
- ); - }.bind(this)) - } -
- ) : ( -
- { - 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)) - } -
- ) - } +
+ { + 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)) + } +
diff --git a/ui/zerotier.css b/ui/zerotier.css index cde5cea8..e5c58838 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 #000000; } .zeroTierNode > .middle > .middleCell > .middleScroll { display: block; @@ -87,76 +60,19 @@ 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; + background: #000000; color: #ffffff; } .zeroTierNode > .bottom > .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;ss;++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;a0){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;aa;++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 Date: Mon, 16 Nov 2015 14:45:17 -0800 Subject: . --- cluster-geo/cluster-geo/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cluster-geo/cluster-geo/package.json b/cluster-geo/cluster-geo/package.json index 4cd1ce00..53fbc5f4 100644 --- a/cluster-geo/cluster-geo/package.json +++ b/cluster-geo/cluster-geo/package.json @@ -11,6 +11,6 @@ "dependencies": { "geoip2ws": "^1.7.1", "leveldown": "^1.4.2", - "levelup": "^1.2.1" + "levelup": "^1.3.0" } } -- cgit v1.2.3 From 38fe77ecf29370dc1b9dfdec0ddf897cf4348ef5 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 16 Nov 2015 15:44:07 -0800 Subject: WebUIWrapper is dead. --- windows/WebUIWrapper/App.config | 6 - windows/WebUIWrapper/Form1.Designer.cs | 66 - windows/WebUIWrapper/Form1.cs | 74 - windows/WebUIWrapper/Form1.resx | 6293 -------------------- windows/WebUIWrapper/Program.cs | 92 - windows/WebUIWrapper/Properties/AssemblyInfo.cs | 36 - .../WebUIWrapper/Properties/Resources.Designer.cs | 63 - windows/WebUIWrapper/Properties/Resources.resx | 117 - .../WebUIWrapper/Properties/Settings.Designer.cs | 26 - windows/WebUIWrapper/Properties/Settings.settings | 7 - windows/WebUIWrapper/Properties/app.manifest | 52 - windows/WebUIWrapper/WebUIWrapper.csproj | 144 - windows/WebUIWrapper/ZeroTierIcon.ico | Bin 370070 -> 0 bytes windows/ZeroTierOne.sln | 79 - 14 files changed, 7055 deletions(-) delete mode 100644 windows/WebUIWrapper/App.config delete mode 100644 windows/WebUIWrapper/Form1.Designer.cs delete mode 100644 windows/WebUIWrapper/Form1.cs delete mode 100644 windows/WebUIWrapper/Form1.resx delete mode 100644 windows/WebUIWrapper/Program.cs delete mode 100644 windows/WebUIWrapper/Properties/AssemblyInfo.cs delete mode 100644 windows/WebUIWrapper/Properties/Resources.Designer.cs delete mode 100644 windows/WebUIWrapper/Properties/Resources.resx delete mode 100644 windows/WebUIWrapper/Properties/Settings.Designer.cs delete mode 100644 windows/WebUIWrapper/Properties/Settings.settings delete mode 100644 windows/WebUIWrapper/Properties/app.manifest delete mode 100644 windows/WebUIWrapper/WebUIWrapper.csproj delete mode 100644 windows/WebUIWrapper/ZeroTierIcon.ico diff --git a/windows/WebUIWrapper/App.config b/windows/WebUIWrapper/App.config deleted file mode 100644 index 8e156463..00000000 --- a/windows/WebUIWrapper/App.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file 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 - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - 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 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - - - 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= - - - \ 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"); - - /// - /// The main entry point for the application. - /// - [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/Resources.Designer.cs b/windows/WebUIWrapper/Properties/Resources.Designer.cs deleted file mode 100644 index 463c7ea3..00000000 --- a/windows/WebUIWrapper/Properties/Resources.Designer.cs +++ /dev/null @@ -1,63 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.34209 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace WebUIWrapper.Properties { - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [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 { - - 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() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [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); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - } -} diff --git a/windows/WebUIWrapper/Properties/Resources.resx b/windows/WebUIWrapper/Properties/Resources.resx deleted file mode 100644 index af7dbebb..00000000 --- a/windows/WebUIWrapper/Properties/Resources.resx +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/windows/WebUIWrapper/Properties/Settings.Designer.cs b/windows/WebUIWrapper/Properties/Settings.Designer.cs deleted file mode 100644 index 8115e015..00000000 --- a/windows/WebUIWrapper/Properties/Settings.Designer.cs +++ /dev/null @@ -1,26 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.34209 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace WebUIWrapper.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 { - - private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); - - public static Settings Default { - get { - return defaultInstance; - } - } - } -} 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 @@ - - - - - - - diff --git a/windows/WebUIWrapper/Properties/app.manifest b/windows/WebUIWrapper/Properties/app.manifest deleted file mode 100644 index 4e1881fb..00000000 --- a/windows/WebUIWrapper/Properties/app.manifest +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/windows/WebUIWrapper/WebUIWrapper.csproj b/windows/WebUIWrapper/WebUIWrapper.csproj deleted file mode 100644 index 44fef263..00000000 --- a/windows/WebUIWrapper/WebUIWrapper.csproj +++ /dev/null @@ -1,144 +0,0 @@ - - - - - Debug - AnyCPU - {04832129-0F0C-438B-ACDF-8BB7F99AE241} - WinExe - Properties - WebUIWrapper - ZeroTier One - v4.5 - 512 - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - x86 - pdbonly - true - bin\Release\ - - - prompt - 4 - - - WebUIWrapper.Program - - - false - - - LocalIntranet - - - false - - - Properties\app.manifest - - - ZeroTierIcon.ico - - - - - - - - - - - - - - - - Form - - - Form1.cs - - - - - Form1.cs - - - ResXFileCodeGenerator - Resources.Designer.cs - Designer - - - True - Resources.resx - True - - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - True - Settings.settings - True - - - - - - - - False - Microsoft .NET Framework 4.5 %28x86 and x64%29 - true - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - false - - - - - - - - \ No newline at end of file diff --git a/windows/WebUIWrapper/ZeroTierIcon.ico b/windows/WebUIWrapper/ZeroTierIcon.ico deleted file mode 100644 index 2d190c47..00000000 Binary files a/windows/WebUIWrapper/ZeroTierIcon.ico and /dev/null differ diff --git a/windows/ZeroTierOne.sln b/windows/ZeroTierOne.sln index a2c65bd9..68596187 100644 --- a/windows/ZeroTierOne.sln +++ b/windows/ZeroTierOne.sln @@ -5,8 +5,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZeroTierOne", "ZeroTierOne\ 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}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WinUI", "WinUI\WinUI.csproj", "{4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}" EndProject Global @@ -339,83 +337,6 @@ 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 -- cgit v1.2.3 From e4d1aba3f82c1265579b0b9dfba22903e34ae7d1 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 16 Nov 2015 16:19:24 -0800 Subject: Use new OSX tap version, and update OSX install scripts. --- .../com.zerotier.tap.kext/Contents/Info.plist | 36 ------- .../com.zerotier.tap.kext/Contents/MacOS/tap | Bin 50496 -> 0 bytes .../Contents/_CodeSignature/CodeResources | 105 --------------------- ext/bin/tap-mac/tap.kext.old/Contents/Info.plist | 36 +++++++ ext/bin/tap-mac/tap.kext.old/Contents/MacOS/tap | Bin 0 -> 81240 bytes .../Contents/_CodeSignature/CodeDirectory | Bin 0 -> 145 bytes .../Contents/_CodeSignature/CodeRequirements | Bin 0 -> 176 bytes .../Contents/_CodeSignature/CodeResources | 105 +++++++++++++++++++++ .../Contents/_CodeSignature/CodeSignature | Bin 0 -> 8578 bytes ext/bin/tap-mac/tap.kext/Contents/Info.plist | 2 +- ext/bin/tap-mac/tap.kext/Contents/MacOS/tap | Bin 81240 -> 50496 bytes .../tap.kext/Contents/_CodeSignature/CodeDirectory | Bin 145 -> 0 bytes .../Contents/_CodeSignature/CodeRequirements | Bin 176 -> 0 bytes .../tap.kext/Contents/_CodeSignature/CodeSignature | Bin 8578 -> 0 bytes ext/installfiles/mac/launch.sh | 10 +- ext/installfiles/mac/postinst.sh | 6 +- 16 files changed, 147 insertions(+), 153 deletions(-) delete mode 100644 ext/bin/tap-mac/com.zerotier.tap.kext/Contents/Info.plist delete mode 100755 ext/bin/tap-mac/com.zerotier.tap.kext/Contents/MacOS/tap delete mode 100644 ext/bin/tap-mac/com.zerotier.tap.kext/Contents/_CodeSignature/CodeResources create mode 100644 ext/bin/tap-mac/tap.kext.old/Contents/Info.plist create mode 100755 ext/bin/tap-mac/tap.kext.old/Contents/MacOS/tap create mode 100644 ext/bin/tap-mac/tap.kext.old/Contents/_CodeSignature/CodeDirectory create mode 100644 ext/bin/tap-mac/tap.kext.old/Contents/_CodeSignature/CodeRequirements create mode 100644 ext/bin/tap-mac/tap.kext.old/Contents/_CodeSignature/CodeResources create mode 100644 ext/bin/tap-mac/tap.kext.old/Contents/_CodeSignature/CodeSignature delete mode 100644 ext/bin/tap-mac/tap.kext/Contents/_CodeSignature/CodeDirectory delete mode 100644 ext/bin/tap-mac/tap.kext/Contents/_CodeSignature/CodeRequirements delete mode 100644 ext/bin/tap-mac/tap.kext/Contents/_CodeSignature/CodeSignature diff --git a/ext/bin/tap-mac/com.zerotier.tap.kext/Contents/Info.plist b/ext/bin/tap-mac/com.zerotier.tap.kext/Contents/Info.plist deleted file mode 100644 index c20eefa5..00000000 --- a/ext/bin/tap-mac/com.zerotier.tap.kext/Contents/Info.plist +++ /dev/null @@ -1,36 +0,0 @@ - - - - - CFBundleDevelopmentRegion - English - CFBundleExecutable - tap - CFBundleIdentifier - com.zerotier.tap - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - tap - CFBundlePackageType - KEXT - CFBundleShortVersionString - 20150118 - CFBundleSignature - ???? - CFBundleVersion - 1.0 - OSBundleLibraries - - com.apple.kpi.mach - 8.0 - com.apple.kpi.bsd - 8.0 - com.apple.kpi.libkern - 8.0 - com.apple.kpi.unsupported - 8.0 - - - - diff --git a/ext/bin/tap-mac/com.zerotier.tap.kext/Contents/MacOS/tap b/ext/bin/tap-mac/com.zerotier.tap.kext/Contents/MacOS/tap deleted file mode 100755 index 48bf9625..00000000 Binary files a/ext/bin/tap-mac/com.zerotier.tap.kext/Contents/MacOS/tap and /dev/null differ diff --git a/ext/bin/tap-mac/com.zerotier.tap.kext/Contents/_CodeSignature/CodeResources b/ext/bin/tap-mac/com.zerotier.tap.kext/Contents/_CodeSignature/CodeResources deleted file mode 100644 index 0710b400..00000000 --- a/ext/bin/tap-mac/com.zerotier.tap.kext/Contents/_CodeSignature/CodeResources +++ /dev/null @@ -1,105 +0,0 @@ - - - - - files - - files2 - - rules - - ^Resources/ - - ^Resources/.*\.lproj/ - - optional - - weight - 1000 - - ^Resources/.*\.lproj/locversion.plist$ - - omit - - weight - 1100 - - ^version.plist$ - - - rules2 - - .*\.dSYM($|/) - - weight - 11 - - ^(.*/)?\.DS_Store$ - - omit - - weight - 2000 - - ^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/ - - nested - - weight - 10 - - ^.* - - ^Info\.plist$ - - omit - - weight - 20 - - ^PkgInfo$ - - omit - - weight - 20 - - ^Resources/ - - weight - 20 - - ^Resources/.*\.lproj/ - - optional - - weight - 1000 - - ^Resources/.*\.lproj/locversion.plist$ - - omit - - weight - 1100 - - ^[^/]+$ - - nested - - weight - 10 - - ^embedded\.provisionprofile$ - - weight - 20 - - ^version\.plist$ - - weight - 20 - - - - 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 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + tap + CFBundleIdentifier + com.zerotier.tap + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + tap + CFBundlePackageType + KEXT + CFBundleShortVersionString + 20131028 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + OSBundleLibraries + + com.apple.kpi.mach + 8.0 + com.apple.kpi.bsd + 8.0 + com.apple.kpi.libkern + 8.0 + com.apple.kpi.unsupported + 8.0 + + + + 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 Binary files /dev/null and b/ext/bin/tap-mac/tap.kext.old/Contents/MacOS/tap differ diff --git a/ext/bin/tap-mac/tap.kext.old/Contents/_CodeSignature/CodeDirectory b/ext/bin/tap-mac/tap.kext.old/Contents/_CodeSignature/CodeDirectory new file mode 100644 index 00000000..58c421c2 Binary files /dev/null and b/ext/bin/tap-mac/tap.kext.old/Contents/_CodeSignature/CodeDirectory differ diff --git a/ext/bin/tap-mac/tap.kext.old/Contents/_CodeSignature/CodeRequirements b/ext/bin/tap-mac/tap.kext.old/Contents/_CodeSignature/CodeRequirements new file mode 100644 index 00000000..1df93129 Binary files /dev/null and b/ext/bin/tap-mac/tap.kext.old/Contents/_CodeSignature/CodeRequirements 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 @@ + + + + + files + + files2 + + rules + + ^Resources/ + + ^Resources/.*\.lproj/ + + optional + + weight + 1000 + + ^Resources/.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^version.plist$ + + + rules2 + + .*\.dSYM($|/) + + weight + 11 + + ^(.*/)?\.DS_Store$ + + omit + + weight + 2000 + + ^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/ + + nested + + weight + 10 + + ^.* + + ^Info\.plist$ + + omit + + weight + 20 + + ^PkgInfo$ + + omit + + weight + 20 + + ^Resources/ + + weight + 20 + + ^Resources/.*\.lproj/ + + optional + + weight + 1000 + + ^Resources/.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^[^/]+$ + + nested + + weight + 10 + + ^embedded\.provisionprofile$ + + weight + 20 + + ^version\.plist$ + + weight + 20 + + + + diff --git a/ext/bin/tap-mac/tap.kext.old/Contents/_CodeSignature/CodeSignature b/ext/bin/tap-mac/tap.kext.old/Contents/_CodeSignature/CodeSignature new file mode 100644 index 00000000..64429727 Binary files /dev/null and b/ext/bin/tap-mac/tap.kext.old/Contents/_CodeSignature/CodeSignature 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 @@ CFBundlePackageType KEXT CFBundleShortVersionString - 20131028 + 20150118 CFBundleSignature ???? CFBundleVersion 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 Binary files a/ext/bin/tap-mac/tap.kext/Contents/MacOS/tap and b/ext/bin/tap-mac/tap.kext/Contents/MacOS/tap differ diff --git a/ext/bin/tap-mac/tap.kext/Contents/_CodeSignature/CodeDirectory b/ext/bin/tap-mac/tap.kext/Contents/_CodeSignature/CodeDirectory deleted file mode 100644 index 58c421c2..00000000 Binary files a/ext/bin/tap-mac/tap.kext/Contents/_CodeSignature/CodeDirectory and /dev/null differ diff --git a/ext/bin/tap-mac/tap.kext/Contents/_CodeSignature/CodeRequirements b/ext/bin/tap-mac/tap.kext/Contents/_CodeSignature/CodeRequirements deleted file mode 100644 index 1df93129..00000000 Binary files a/ext/bin/tap-mac/tap.kext/Contents/_CodeSignature/CodeRequirements and /dev/null differ diff --git a/ext/bin/tap-mac/tap.kext/Contents/_CodeSignature/CodeSignature b/ext/bin/tap-mac/tap.kext/Contents/_CodeSignature/CodeSignature deleted file mode 100644 index 64429727..00000000 Binary files a/ext/bin/tap-mac/tap.kext/Contents/_CodeSignature/CodeSignature and /dev/null differ 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 987e131b..47d9ddd9 100755 --- a/ext/installfiles/mac/postinst.sh +++ b/ext/installfiles/mac/postinst.sh @@ -6,10 +6,12 @@ launchctl unload /Library/LaunchDaemons/com.zerotier.one.plist >>/dev/null 2>&1 cd "/Library/Application Support/ZeroTier/One" 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 -- cgit v1.2.3 From 906e49ff7200f15d99d0bd2f9d87f484738929b0 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 16 Nov 2015 16:22:41 -0800 Subject: Add make option ZT_ENABLE_CLUSTER and disable it in default Linux build. --- make-freebsd.mk | 5 +++++ make-linux.mk | 7 ++++++- make-mac.mk | 5 +++++ 3 files changed, 16 insertions(+), 1 deletion(-) 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 37e7b7ef..339b548d 100644 --- a/make-linux.mk +++ b/make-linux.mk @@ -29,7 +29,7 @@ endif UNAME_M=$(shell $(CC) -dumpmachine | cut -d '-' -f 1) INCLUDES= -DEFS=-DZT_ENABLE_CLUSTER +DEFS= LDLIBS?= include objects.mk @@ -70,6 +70,11 @@ ifeq ($(ZT_ENABLE_NETWORK_CONTROLLER),1) 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 ifeq ($(ZT_DEBUG),1) DEFS+=-DZT_TRACE diff --git a/make-mac.mk b/make-mac.mk index 174216fb..6ea23859 100644 --- a/make-mac.mk +++ b/make-mac.mk @@ -32,6 +32,11 @@ 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 -- cgit v1.2.3 From 7a53ecac86a24db1ffae066355eef7f3fd59ba90 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 16 Nov 2015 17:18:44 -0800 Subject: UI stuff. --- ui/zerotier.css | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ui/zerotier.css b/ui/zerotier.css index e5c58838..9f72024a 100644 --- a/ui/zerotier.css +++ b/ui/zerotier.css @@ -37,7 +37,7 @@ html,body { width: 100%; height: 100%; display: table-cell; - border-bottom: 1px solid #000000; + border-bottom: 1px solid #cfcfcf; } .zeroTierNode > .middle > .middleCell > .middleScroll { display: block; @@ -72,8 +72,8 @@ html,body { width: 100%; overflow: hidden; display: table-row; - background: #000000; - color: #ffffff; + color: #000000; + background: #dfdfdf; } .zeroTierNode > .bottom > .left { text-align: left; -- cgit v1.2.3 From 37acd375d6e7476f4eb55a25c4ddb6ddeca9d6c8 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 16 Nov 2015 18:10:40 -0800 Subject: Fix 64-bit int warning. --- service/ClusterGeoIpService.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/service/ClusterGeoIpService.cpp b/service/ClusterGeoIpService.cpp index 5e4780b4..f646fe99 100644 --- a/service/ClusterGeoIpService.cpp +++ b/service/ClusterGeoIpService.cpp @@ -44,8 +44,8 @@ #include "../node/Utils.hpp" #include "../osdep/OSUtils.hpp" -// Same as in cluster-geo.js but unlike cluster-geo this cache is volatile -#define ZT_CLUSTERGEOIPSERVICE_INTERNAL_CACHE_TTL (60 * 60 * 24 * 120 * 1000) +// 120 days +#define ZT_CLUSTERGEOIPSERVICE_INTERNAL_CACHE_TTL 10368000000ULL namespace ZeroTier { -- cgit v1.2.3 From a13a21377c2d028d81b5cb26567ebe23bbb2e891 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 16 Nov 2015 18:18:08 -0800 Subject: Delete pre-build miniupnpc for Linux and Mac -- will add Make rules to build from source and include source in ext/ --- ext/bin/miniupnpc/linux-arm32/libminiupnpc.a | Bin 62698 -> 0 bytes ext/bin/miniupnpc/linux-x64/libminiupnpc.a | Bin 87942 -> 0 bytes ext/bin/miniupnpc/linux-x86/libminiupnpc.a | Bin 67782 -> 0 bytes ext/bin/miniupnpc/mac-x64/libminiupnpc.a | Bin 95616 -> 0 bytes 4 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 ext/bin/miniupnpc/linux-arm32/libminiupnpc.a delete mode 100644 ext/bin/miniupnpc/linux-x64/libminiupnpc.a delete mode 100644 ext/bin/miniupnpc/linux-x86/libminiupnpc.a delete mode 100644 ext/bin/miniupnpc/mac-x64/libminiupnpc.a 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 Binary files a/ext/bin/miniupnpc/linux-arm32/libminiupnpc.a and /dev/null 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 Binary files a/ext/bin/miniupnpc/linux-x64/libminiupnpc.a and /dev/null 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 Binary files a/ext/bin/miniupnpc/linux-x86/libminiupnpc.a and /dev/null 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 Binary files a/ext/bin/miniupnpc/mac-x64/libminiupnpc.a and /dev/null differ -- cgit v1.2.3 From cf6164e8477aaa65edd07d136ef1991288feff99 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 16 Nov 2015 18:28:55 -0800 Subject: Build libminiupnpc from source now, and update version. --- .gitignore | 3 + ext/miniupnpc/CMakeLists.txt | 178 +++ ext/miniupnpc/Changelog.txt | 667 +++++++++++ ext/miniupnpc/LICENSE | 27 + ext/miniupnpc/MANIFEST.in | 5 + ext/miniupnpc/Makefile | 379 ++++++ ext/miniupnpc/Makefile.mingw | 98 ++ ext/miniupnpc/README | 61 + ext/miniupnpc/VERSION | 1 + ext/miniupnpc/apiversions.txt | 167 +++ ext/miniupnpc/codelength.h | 54 + ext/miniupnpc/connecthostport.c | 264 +++++ ext/miniupnpc/connecthostport.h | 18 + ext/miniupnpc/external-ip.sh | 4 + ext/miniupnpc/igd_desc_parse.c | 123 ++ ext/miniupnpc/igd_desc_parse.h | 49 + ext/miniupnpc/java/JavaBridgeTest.java | 97 ++ ext/miniupnpc/java/testjava.bat | 8 + ext/miniupnpc/java/testjava.sh | 8 + ext/miniupnpc/listdevices.c | 110 ++ ext/miniupnpc/man3/miniupnpc.3 | 55 + ext/miniupnpc/mingw32make.bat | 8 + ext/miniupnpc/minihttptestserver.c | 655 +++++++++++ ext/miniupnpc/minisoap.c | 123 ++ ext/miniupnpc/minisoap.h | 15 + ext/miniupnpc/minissdpc.c | 849 ++++++++++++++ ext/miniupnpc/minissdpc.h | 58 + ext/miniupnpc/miniupnpc.c | 684 +++++++++++ ext/miniupnpc/miniupnpc.def | 45 + ext/miniupnpc/miniupnpc.h | 152 +++ ext/miniupnpc/miniupnpc_declspec.h | 21 + ext/miniupnpc/miniupnpcmodule.c | 695 +++++++++++ ext/miniupnpc/miniupnpcstrings.h.cmake | 15 + ext/miniupnpc/miniupnpcstrings.h.in | 23 + ext/miniupnpc/miniupnpctypes.h | 19 + ext/miniupnpc/miniwget.c | 626 ++++++++++ ext/miniupnpc/miniwget.h | 30 + ext/miniupnpc/minixml.c | 229 ++++ ext/miniupnpc/minixml.h | 37 + ext/miniupnpc/minixmlvalid.c | 163 +++ ext/miniupnpc/msvc/miniupnpc.sln | 29 + ext/miniupnpc/msvc/miniupnpc.vcproj | 283 +++++ ext/miniupnpc/msvc/upnpc-static.vcproj | 195 +++ ext/miniupnpc/portlistingparse.c | 172 +++ ext/miniupnpc/portlistingparse.h | 65 + ext/miniupnpc/pymoduletest.py | 88 ++ ext/miniupnpc/receivedata.c | 105 ++ ext/miniupnpc/receivedata.h | 19 + ext/miniupnpc/setup.py | 28 + ext/miniupnpc/setupmingw32.py | 28 + ext/miniupnpc/testdesc/linksys_WAG200G_desc.values | 14 + ext/miniupnpc/testdesc/linksys_WAG200G_desc.xml | 110 ++ ext/miniupnpc/testdesc/new_LiveBox_desc.values | 20 + ext/miniupnpc/testdesc/new_LiveBox_desc.xml | 90 ++ ext/miniupnpc/testigddescparse.c | 187 +++ ext/miniupnpc/testminiwget.c | 53 + ext/miniupnpc/testminiwget.sh | 96 ++ ext/miniupnpc/testminixml.c | 89 ++ ext/miniupnpc/testportlistingparse.c | 151 +++ .../testreplyparse/DeletePortMapping.namevalue | 3 + ext/miniupnpc/testreplyparse/DeletePortMapping.xml | 6 + .../testreplyparse/GetExternalIPAddress.namevalue | 2 + .../testreplyparse/GetExternalIPAddress.xml | 2 + .../GetSpecificPortMappingEntryReq.namevalue | 3 + .../GetSpecificPortMappingEntryReq.xml | 3 + .../GetSpecificPortMappingEntryResp.namevalue | 5 + .../GetSpecificPortMappingEntryResp.xml | 2 + .../SetDefaultConnectionService.namevalue | 1 + .../testreplyparse/SetDefaultConnectionService.xml | 1 + ext/miniupnpc/testreplyparse/readme.txt | 7 + ext/miniupnpc/testupnpigd.py | 84 ++ ext/miniupnpc/testupnpreplyparse.c | 96 ++ ext/miniupnpc/testupnpreplyparse.sh | 14 + ext/miniupnpc/updateminiupnpcstrings.sh | 53 + ext/miniupnpc/upnpc.c | 833 +++++++++++++ ext/miniupnpc/upnpcommands.c | 1237 ++++++++++++++++++++ ext/miniupnpc/upnpcommands.h | 348 ++++++ ext/miniupnpc/upnpdev.c | 23 + ext/miniupnpc/upnpdev.h | 36 + ext/miniupnpc/upnperrors.c | 107 ++ ext/miniupnpc/upnperrors.h | 26 + ext/miniupnpc/upnpreplyparse.c | 197 ++++ ext/miniupnpc/upnpreplyparse.h | 63 + ext/miniupnpc/wingenminiupnpcstrings.c | 83 ++ make-mac.mk | 14 +- 85 files changed, 11889 insertions(+), 5 deletions(-) create mode 100644 ext/miniupnpc/CMakeLists.txt create mode 100644 ext/miniupnpc/Changelog.txt create mode 100644 ext/miniupnpc/LICENSE create mode 100644 ext/miniupnpc/MANIFEST.in create mode 100644 ext/miniupnpc/Makefile create mode 100644 ext/miniupnpc/Makefile.mingw create mode 100644 ext/miniupnpc/README create mode 100644 ext/miniupnpc/VERSION create mode 100644 ext/miniupnpc/apiversions.txt create mode 100644 ext/miniupnpc/codelength.h create mode 100644 ext/miniupnpc/connecthostport.c create mode 100644 ext/miniupnpc/connecthostport.h create mode 100755 ext/miniupnpc/external-ip.sh create mode 100644 ext/miniupnpc/igd_desc_parse.c create mode 100644 ext/miniupnpc/igd_desc_parse.h create mode 100644 ext/miniupnpc/java/JavaBridgeTest.java create mode 100755 ext/miniupnpc/java/testjava.bat create mode 100755 ext/miniupnpc/java/testjava.sh create mode 100644 ext/miniupnpc/listdevices.c create mode 100644 ext/miniupnpc/man3/miniupnpc.3 create mode 100644 ext/miniupnpc/mingw32make.bat create mode 100644 ext/miniupnpc/minihttptestserver.c create mode 100644 ext/miniupnpc/minisoap.c create mode 100644 ext/miniupnpc/minisoap.h create mode 100644 ext/miniupnpc/minissdpc.c create mode 100644 ext/miniupnpc/minissdpc.h create mode 100644 ext/miniupnpc/miniupnpc.c create mode 100644 ext/miniupnpc/miniupnpc.def create mode 100644 ext/miniupnpc/miniupnpc.h create mode 100644 ext/miniupnpc/miniupnpc_declspec.h create mode 100644 ext/miniupnpc/miniupnpcmodule.c create mode 100644 ext/miniupnpc/miniupnpcstrings.h.cmake create mode 100644 ext/miniupnpc/miniupnpcstrings.h.in create mode 100644 ext/miniupnpc/miniupnpctypes.h create mode 100644 ext/miniupnpc/miniwget.c create mode 100644 ext/miniupnpc/miniwget.h create mode 100644 ext/miniupnpc/minixml.c create mode 100644 ext/miniupnpc/minixml.h create mode 100644 ext/miniupnpc/minixmlvalid.c create mode 100644 ext/miniupnpc/msvc/miniupnpc.sln create mode 100644 ext/miniupnpc/msvc/miniupnpc.vcproj create mode 100644 ext/miniupnpc/msvc/upnpc-static.vcproj create mode 100644 ext/miniupnpc/portlistingparse.c create mode 100644 ext/miniupnpc/portlistingparse.h create mode 100644 ext/miniupnpc/pymoduletest.py create mode 100644 ext/miniupnpc/receivedata.c create mode 100644 ext/miniupnpc/receivedata.h create mode 100644 ext/miniupnpc/setup.py create mode 100644 ext/miniupnpc/setupmingw32.py create mode 100644 ext/miniupnpc/testdesc/linksys_WAG200G_desc.values create mode 100644 ext/miniupnpc/testdesc/linksys_WAG200G_desc.xml create mode 100644 ext/miniupnpc/testdesc/new_LiveBox_desc.values create mode 100644 ext/miniupnpc/testdesc/new_LiveBox_desc.xml create mode 100644 ext/miniupnpc/testigddescparse.c create mode 100644 ext/miniupnpc/testminiwget.c create mode 100755 ext/miniupnpc/testminiwget.sh create mode 100644 ext/miniupnpc/testminixml.c create mode 100644 ext/miniupnpc/testportlistingparse.c create mode 100644 ext/miniupnpc/testreplyparse/DeletePortMapping.namevalue create mode 100644 ext/miniupnpc/testreplyparse/DeletePortMapping.xml create mode 100644 ext/miniupnpc/testreplyparse/GetExternalIPAddress.namevalue create mode 100644 ext/miniupnpc/testreplyparse/GetExternalIPAddress.xml create mode 100644 ext/miniupnpc/testreplyparse/GetSpecificPortMappingEntryReq.namevalue create mode 100644 ext/miniupnpc/testreplyparse/GetSpecificPortMappingEntryReq.xml create mode 100644 ext/miniupnpc/testreplyparse/GetSpecificPortMappingEntryResp.namevalue create mode 100644 ext/miniupnpc/testreplyparse/GetSpecificPortMappingEntryResp.xml create mode 100644 ext/miniupnpc/testreplyparse/SetDefaultConnectionService.namevalue create mode 100644 ext/miniupnpc/testreplyparse/SetDefaultConnectionService.xml create mode 100644 ext/miniupnpc/testreplyparse/readme.txt create mode 100755 ext/miniupnpc/testupnpigd.py create mode 100644 ext/miniupnpc/testupnpreplyparse.c create mode 100755 ext/miniupnpc/testupnpreplyparse.sh create mode 100755 ext/miniupnpc/updateminiupnpcstrings.sh create mode 100644 ext/miniupnpc/upnpc.c create mode 100644 ext/miniupnpc/upnpcommands.c create mode 100644 ext/miniupnpc/upnpcommands.h create mode 100644 ext/miniupnpc/upnpdev.c create mode 100644 ext/miniupnpc/upnpdev.h create mode 100644 ext/miniupnpc/upnperrors.c create mode 100644 ext/miniupnpc/upnperrors.h create mode 100644 ext/miniupnpc/upnpreplyparse.c create mode 100644 ext/miniupnpc/upnpreplyparse.h create mode 100644 ext/miniupnpc/wingenminiupnpcstrings.c diff --git a/.gitignore b/.gitignore index f7a41b45..0ddbbb88 100755 --- a/.gitignore +++ b/.gitignore @@ -44,6 +44,9 @@ Thumbs.db *.pid *.pkg *.o +*.a +*.dylib +*.so *.o-* *.core *.deb 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/miniupnpc/Changelog.txt b/ext/miniupnpc/Changelog.txt new file mode 100644 index 00000000..bef61f59 --- /dev/null +++ b/ext/miniupnpc/Changelog.txt @@ -0,0 +1,667 @@ +$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 + +2015/06/16: + update getDevicesFromMiniSSDPD() to process longer minissdpd + responses + +2015/05/22: + add searchalltypes param to upnpDiscoverDevices() + increments API_VERSION to 13 + +2015/04/30: + upnpc: output version on the terminal + +2015/04/27: + _BSD_SOURCE is deprecated in favor of _DEFAULT_SOURCE + fix CMakeLists.txt COMPILE_DEFINITIONS + fix getDevicesFromMiniSSDPD() not setting scope_id + improve -r command of upnpc command line tool + +2014/11/17: + search all : + upnpDiscoverDevices() / upnpDiscoverAll() functions + listdevices executable + increment API_VERSION to 12 + validate igd_desc_parse + +2014/11/13: + increment API_VERSION to 11 + +2014/11/05: + simplified function GetUPNPUrls() + +2014/09/11: + use remoteHost arg of DeletePortMapping + +2014/09/06: + Fix python3 build + +2014/07/01: + Fix parsing of IGD2 root descriptions + +2014/06/10: + rename LIBSPEC to MINIUPNP_LIBSPEC + +2014/05/15: + Add support for IGD2 AddAnyPortMapping and DeletePortMappingRange + +2014/02/05: + handle EINPROGRESS after connect() + +2014/02/03: + minixml now handle XML comments + +VERSION 1.9 : released 2014/01/31 + +2014/01/31: + added argument remoteHost to UPNP_GetSpecificPortMappingEntry() + increment API_VERSION to 10 + +2013/12/09: + --help and -h arguments in upnpc.c + +2013/10/07: + fixed potential buffer overrun in miniwget.c + Modified UPNP_GetValidIGD() to check for ExternalIpAddress + +2013/08/01: + define MAXHOSTNAMELEN if not already done + +2013/06/06: + update upnpreplyparse to allow larger values (128 chars instead of 64) + +2013/05/14: + Update upnpreplyparse to take into account "empty" elements + validate upnpreplyparse.c code with "make check" + +2013/05/03: + Fix Solaris build thanks to Maciej Małecki + +2013/04/27: + Fix testminiwget.sh for BSD + +2013/03/23: + Fixed Makefile for *BSD + +2013/03/11: + Update Makefile to use JNAerator version 0.11 + +2013/02/11: + Fix testminiwget.sh for use with dash + Use $(DESTDIR) in Makefile + +VERSION 1.8 : released 2013/02/06 + +2012/10/16: + fix testminiwget with no IPv6 support + +2012/09/27: + Rename all include guards to not clash with C99 + (7.1.3 Reserved identifiers). + +2012/08/30: + Added -e option to upnpc program (set description for port mappings) + +2012/08/29: + Python 3 support (thanks to Christopher Foo) + +2012/08/11: + Fix a memory link in UPNP_GetValidIGD() + Try to handle scope id in link local IPv6 URL under MS Windows + +2012/07/20: + Disable HAS_IP_MREQN on DragonFly BSD + +2012/06/28: + GetUPNPUrls() now inserts scope into link-local IPv6 addresses + +2012/06/23: + More error return checks in upnpc.c + #define MINIUPNPC_GET_SRC_ADDR enables receivedata() to get scope_id + parseURL() now parses IPv6 addresses scope + new parameter for miniwget() : IPv6 address scope + increment API_VERSION to 9 + +2012/06/20: + fixed CMakeLists.txt + +2012/05/29 + Improvements in testminiwget.sh + +VERSION 1.7 : released 2012/05/24 + +2012/05/01: + Cleanup settings of CFLAGS in Makefile + Fix signed/unsigned integer comparaisons + +2012/04/20: + Allow to specify protocol with TCP or UDP for -A option + +2012/04/09: + Only try to fetch XML description once in UPNP_GetValidIGD() + Added -ansi flag to compilation, and fixed C++ comments to ANSI C comments. + +2012/04/05: + minor improvements to minihttptestserver.c + +2012/03/15: + upnperrors.c returns valid error string for unrecognized error codes + +2012/03/08: + make minihttptestserver listen on loopback interface instead of 0.0.0.0 + +2012/01/25: + Maven installation thanks to Alexey Kuznetsov + +2012/01/21: + Replace WIN32 macro by _WIN32 + +2012/01/19: + Fixes in java wrappers thanks to Alexey Kuznetsov : + https://github.com/axet/miniupnp/tree/fix-javatest/miniupnpc + Make and install .deb packages (python) thanks to Alexey Kuznetsov : + https://github.com/axet/miniupnp/tree/feature-debbuild/miniupnpc + +2012/01/07: + The multicast interface can now be specified by name with IPv4. + +2012/01/02: + Install man page + +2011/11/25: + added header to Port Mappings list in upnpc.c + +2011/10/09: + Makefile : make clean now removes jnaerator generated files. + MINIUPNPC_VERSION in miniupnpc.h (updated by make) + +2011/09/12: + added rootdescURL to UPNPUrls structure. + +VERSION 1.6 : released 2011/07/25 + +2011/07/25: + Update doc for version 1.6 release + +2011/06/18: + Fix for windows in miniwget.c + +2011/06/04: + display remote host in port mapping listing + +2011/06/03: + Fix in make install : there were missing headers + +2011/05/26: + Fix the socket leak in miniwget thanks to Richard Marsh. + Permit to add leaseduration in -a command. Display lease duration. + +2011/05/15: + Try both LinkLocal and SiteLocal multicast address for SSDP in IPv6 + +2011/05/09: + add a test in testminiwget.sh. + more error checking in miniwget.c + +2011/05/06: + Adding some tool to test and validate miniwget.c + simplified and debugged miniwget.c + +2011/04/11: + moving ReceiveData() to a receivedata.c file. + parsing presentation url + adding IGD v2 WANIPv6FirewallControl commands + +2011/04/10: + update of miniupnpcmodule.c + comments in miniwget.c, update in testminiwget + Adding errors codes from IGD v2 + new functions in upnpc.c for IGD v2 + +2011/04/09: + Support for litteral ip v6 address in miniwget + +2011/04/08: + Adding support for urn:schemas-upnp-org:service:WANIPv6FirewallControl:1 + Updating APIVERSION + Supporting IPV6 in upnpDiscover() + Adding a -6 option to upnpc command line tool + +2011/03/18: + miniwget/parseURL() : return an error when url param is null. + fixing GetListOfPortMappings() + +2011/03/14: + upnpDiscover() now reporting an error code. + improvements in comments. + +2011/03/11: + adding miniupnpcstrings.h.cmake and CMakeLists.txt files. + +2011/02/15: + Implementation of GetListOfPortMappings() + +2011/02/07: + updates to minixml to support character data starting with spaces + minixml now support CDATA + upnpreplyparse treats specificaly + change in simpleUPnPcommand to return the buffer (simplification) + +2011/02/06: + Added leaseDuration argument to AddPortMapping() + Starting to implement GetListOfPortMappings() + +2011/01/11: + updating wingenminiupnpcstrings.c + +2011/01/04: + improving updateminiupnpcstrings.sh + +VERSION 1.5 : released 2011/01/01 + +2010/12/21: + use NO_GETADDRINFO macro to disable the use of getaddrinfo/freeaddrinfo + +2010/12/11: + Improvements on getHTTPResponse() code. + +2010/12/09: + new code for miniwget that handle Chunked transfer encoding + using getHTTPResponse() in SOAP call code + Adding MANIFEST.in for 'python setup.py bdist_rpm' + +2010/11/25: + changes to minissdpc.c to compile under Win32. + see http://miniupnp.tuxfamily.org/forum/viewtopic.php?t=729 + +2010/09/17: + Various improvement to Makefile from Michał Górny + +2010/08/05: + Adding the script "external-ip.sh" from Reuben Hawkins + +2010/06/09: + update to python module to match modification made on 2010/04/05 + update to Java test code to match modification made on 2010/04/05 + all UPNP_* function now return an error if the SOAP request failed + at HTTP level. + +2010/04/17: + Using GetBestRoute() under win32 in order to find the + right interface to use. + +2010/04/12: + Retrying with HTTP/1.1 if HTTP/1.0 failed. see + http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=1703 + +2010/04/07: + avoid returning duplicates in upnpDiscover() + +2010/04/05: + Create a connecthostport.h/.c with connecthostport() function + and use it in miniwget and miniupnpc. + Use getnameinfo() instead of inet_ntop or inet_ntoa + Work to make miniupnpc IPV6 compatible... + Add java test code. + Big changes in order to support device having both WANIPConnection + and WANPPPConnection. + +2010/04/04: + Use getaddrinfo() instead of gethostbyname() in miniwget. + +2010/01/06: + #define _DARWIN_C_SOURCE for Mac OS X + +2009/12/19: + Improve MinGW32 build + +2009/12/11: + adding a MSVC9 project to build the static library and executable + +2009/12/10: + Fixing some compilation stuff for Windows/MinGW + +2009/12/07: + adaptations in Makefile and updateminiupnpcstring.sh for AmigaOS + some fixes for Windows when using virtual ethernet adapters (it is the + case with VMWare installed). + +2009/12/04: + some fixes for AmigaOS compilation + Changed HTTP version to HTTP/1.0 for Soap too (to prevent chunked + transfer encoding) + +2009/12/03: + updating printIDG and testigddescparse.c for debug. + modifications to compile under AmigaOS + adding a testminiwget program + Changed miniwget to advertise itself as HTTP/1.0 to prevent chunked + transfer encoding + +2009/11/26: + fixing updateminiupnpcstrings.sh to take into account + which command that does not return an error code. + +VERSION 1.4 : released 2009/10/30 + +2009/10/16: + using Py_BEGIN_ALLOW_THREADS and Py_END_ALLOW_THREADS in python module. + +2009/10/10: + Some fixes for compilation under Solaris + compilation fixes : http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=1464 + +2009/09/21: + fixing the code to ignore EINTR during connect() calls. + +2009/08/07: + Set socket timeout for connect() + Some cleanup in miniwget.c + +2009/08/04: + remove multiple redirections with -d in upnpc.c + Print textual error code in upnpc.c + Ignore EINTR during the connect() and poll() calls. + +2009/07/29: + fix in updateminiupnpcstrings.sh if OS name contains "/" + Sending a correct value for MX: field in SSDP request + +2009/07/20: + Change the Makefile to compile under Mac OS X + Fixed a stackoverflow in getDevicesFromMiniSSDPD() + +2009/07/09: + Compile under Haiku + generate miniupnpcstrings.h.in from miniupnpcstrings.h + +2009/06/04: + patching to compile under CygWin and cross compile for minGW + +VERSION 1.3 : + +2009/04/17: + updating python module + Use strtoull() when using C99 + +2009/02/28: + Fixed miniwget.c for compiling under sun + +2008/12/18: + cleanup in Makefile (thanks to Paul de Weerd) + minissdpc.c : win32 compatibility + miniupnpc.c : changed xmlns prefix from 'm' to 'u' + Removed NDEBUG (using DEBUG) + +2008/10/14: + Added the ExternalHost argument to DeletePortMapping() + +2008/10/11: + Added the ExternalHost argument to AddPortMapping() + Put a correct User-Agent: header in HTTP requests. + +VERSION 1.2 : + +2008/10/07: + Update docs + +2008/09/25: + Integrated sameport patch from Dario Meloni : Added a "sameport" + argument to upnpDiscover(). + +2008/07/18: + small modif to make Clang happy :) + +2008/07/17: + #define SOAPPREFIX "s" in miniupnpc.c in order to remove SOAP-ENV... + +2008/07/14: + include declspec.h in installation (to /usr/include/miniupnpc) + +VERSION 1.1 : + +2008/07/04: + standard options for install/ln instead of gnu-specific stuff. + +2008/07/03: + now builds a .dll and .lib with win32. (mingw32) + +2008/04/28: + make install now install the binary of the upnpc tool + +2008/04/27: + added testupnpigd.py + added error strings for miniupnpc "internal" errors + improved python module error/exception reporting. + +2008/04/23: + Completely rewrite igd_desc_parse.c in order to be compatible with + Linksys WAG200G + Added testigddescparse + updated python module + +VERSION 1.0 : + +2008/02/21: + put some #ifdef DEBUG around DisplayNameValueList() + +2008/02/18: + Improved error reporting in upnpcommands.c + UPNP_GetStatusInfo() returns LastConnectionError + +2008/02/16: + better error handling in minisoap.c + improving display of "valid IGD found" in upnpc.c + +2008/02/03: + Fixing UPNP_GetValidIGD() + improved make install :) + +2007/12/22: + Adding upnperrors.c/h to provide a strupnperror() function + used to translate UPnP error codes to string. + +2007/12/19: + Fixing getDevicesFromMiniSSDPD() + improved error reporting of UPnP functions + +2007/12/18: + It is now possible to specify a different location for MiniSSDPd socket. + working with MiniSSDPd is now more efficient. + python module improved. + +2007/12/16: + improving error reporting + +2007/12/13: + Try to improve compatibility by using HTTP/1.0 instead of 1.1 and + XML a bit different for SOAP. + +2007/11/25: + fixed select() call for linux + +2007/11/15: + Added -fPIC to CFLAG for better shared library code. + +2007/11/02: + Fixed a potential socket leak in miniwget2() + +2007/10/16: + added a parameter to upnpDiscover() in order to allow the use of another + interface than the default multicast interface. + +2007/10/12: + Fixed the creation of symbolic link in Makefile + +2007/10/08: + Added man page + +2007/10/02: + fixed memory bug in GetUPNPUrls() + +2007/10/01: + fixes in the Makefile + Added UPNP_GetIGDFromUrl() and adapted the sample program accordingly. + Added SONAME in the shared library to please debian :) + fixed MS Windows compilation (minissdpd is not available under MS Windows). + +2007/09/25: + small change to Makefile to be able to install in a different location + (default is /usr) + +2007/09/24: + now compiling both shared and static library + +2007/09/19: + Cosmetic changes on upnpc.c + +2007/09/02: + adapting to new miniSSDPd (release version ?) + +2007/08/31: + Usage of miniSSDPd to skip discovery process. + +2007/08/27: + fixed python module to allow compilation with Python older than Python 2.4 + +2007/06/12: + Added a python module. + +2007/05/19: + Fixed compilation under MinGW + +2007/05/15: + fixed a memory leak in AddPortMapping() + Added testupnpreplyparse executable to check the parsing of + upnp soap messages + minixml now ignore namespace prefixes. + +2007/04/26: + upnpc now displays external ip address with -s or -l + +2007/04/11: + changed MINIUPNPC_URL_MAXSIZE to 128 to accomodate the "BT Voyager 210" + +2007/03/19: + cleanup in miniwget.c + +2007/03/01: + Small typo fix... + +2007/01/30: + Now parsing the HTTP header from SOAP responses in order to + get content-length value. + +2007/01/29: + Fixed the Soap Query to speedup the HTTP request. + added some Win32 DLL stuff... + +2007/01/27: + Fixed some WIN32 compatibility issues + +2006/12/14: + Added UPNPIGD_IsConnected() function in miniupnp.c/.h + Added UPNP_GetValidIGD() in miniupnp.c/.h + cleaned upnpc.c main(). now using UPNP_GetValidIGD() + +2006/12/07: + Version 1.0-RC1 released + +2006/12/03: + Minor changes to compile under SunOS/Solaris + +2006/11/30: + made a minixml parser validator program + updated minixml to handle attributes correctly + +2006/11/22: + Added a -r option to the upnpc sample thanks to Alexander Hubmann. + +2006/11/19: + Cleanup code to make it more ANSI C compliant + +2006/11/10: + detect and display local lan address. + +2006/11/04: + Packets and Bytes Sent/Received are now unsigned int. + +2006/11/01: + Bug fix thanks to Giuseppe D'Angelo + +2006/10/31: + C++ compatibility for .h files. + Added a way to get ip Address on the LAN used to reach the IGD. + +2006/10/25: + Added M-SEARCH to the services in the discovery process. + +2006/10/22: + updated the Makefile to use makedepend, added a "make install" + update Makefile + +2006/10/20: + fixing the description url parsing thanks to patch sent by + Wayne Dawe. + Fixed/translated some comments. + Implemented a better discover process, first looking + for IGD then for root devices (as some devices only reply to + M-SEARCH for root devices). + +2006/09/02: + added freeUPNPDevlist() function. + +2006/08/04: + More command line arguments checking + +2006/08/01: + Added the .bat file to compile under Win32 with minGW32 + +2006/07/31: + Fixed the rootdesc parser (igd_desc_parse.c) + +2006/07/20: + parseMSEARCHReply() is now returning the ST: line as well + starting changes to detect several UPnP devices on the network + +2006/07/19: + using GetCommonLinkProperties to get down/upload bitrate + diff --git a/ext/miniupnpc/LICENSE b/ext/miniupnpc/LICENSE new file mode 100644 index 00000000..cb5a0604 --- /dev/null +++ b/ext/miniupnpc/LICENSE @@ -0,0 +1,27 @@ +MiniUPnPc +Copyright (c) 2005-2015, 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. + 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 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/miniupnpc/VERSION b/ext/miniupnpc/VERSION new file mode 100644 index 00000000..2e0e38c6 --- /dev/null +++ b/ext/miniupnpc/VERSION @@ -0,0 +1 @@ +1.9 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/miniupnpc/codelength.h b/ext/miniupnpc/codelength.h new file mode 100644 index 00000000..f5f8e30f --- /dev/null +++ b/ext/miniupnpc/codelength.h @@ -0,0 +1,54 @@ +/* $Id: codelength.h,v 1.5 2015/07/09 12:40:18 nanard Exp $ */ +/* Project : miniupnp + * Author : Thomas BERNARD + * copyright (c) 2005-2015 Thomas Bernard + * This software is subjet to the conditions detailed in the + * provided LICENCE file. */ +#ifndef CODELENGTH_H_INCLUDED +#define CODELENGTH_H_INCLUDED + +/* Encode length by using 7bit per Byte : + * Most significant bit of each byte specifies that the + * following byte is part of the code */ + +/* n : unsigned + * p : unsigned char * + */ +#define DECODELENGTH(n, p) n = 0; \ + do { n = (n << 7) | (*p & 0x7f); } \ + while((*(p++)&0x80) && (n<(1<<25))); + +/* n : unsigned + * READ : function/macro to read one byte (unsigned char) + */ +#define DECODELENGTH_READ(n, READ) \ + n = 0; \ + do { \ + unsigned char c; \ + READ(c); \ + n = (n << 7) | (c & 0x07f); \ + if(!(c&0x80)) break; \ + } while(n<(1<<25)); + +/* n : unsigned + * p : unsigned char * + * p_limit : unsigned char * + */ +#define DECODELENGTH_CHECKLIMIT(n, p, p_limit) \ + n = 0; \ + do { \ + if((p) >= (p_limit)) break; \ + n = (n << 7) | (*(p) & 0x7f); \ + } while((*((p)++)&0x80) && (n<(1<<25))); + + +/* n : unsigned + * p : unsigned char * + */ +#define CODELENGTH(n, p) if(n>=268435456) *(p++) = (n >> 28) | 0x80; \ + if(n>=2097152) *(p++) = (n >> 21) | 0x80; \ + if(n>=16384) *(p++) = (n >> 14) | 0x80; \ + if(n>=128) *(p++) = (n >> 7) | 0x80; \ + *(p++) = n & 0x7f; + +#endif /* CODELENGTH_H_INCLUDED */ diff --git a/ext/miniupnpc/connecthostport.c b/ext/miniupnpc/connecthostport.c new file mode 100644 index 00000000..1f2a032e --- /dev/null +++ b/ext/miniupnpc/connecthostport.c @@ -0,0 +1,264 @@ +/* $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. */ + +/* use getaddrinfo() or gethostbyname() + * uncomment the following line in order to use gethostbyname() */ +#ifdef NO_GETADDRINFO +#define USE_GETHOSTBYNAME +#endif + +#include +#include +#ifdef _WIN32 +#include +#include +#include +#define MAXHOSTNAMELEN 64 +#define snprintf _snprintf +#define herror +#define socklen_t int +#else /* #ifdef _WIN32 */ +#include +#include +#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT +#include +#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ +#include +#include +#include +#define closesocket close +#include +#include +/* defining MINIUPNPC_IGNORE_EINTR enable the ignore of interruptions + * during the connect() call */ +#define MINIUPNPC_IGNORE_EINTR +#ifndef USE_GETHOSTBYNAME +#include +#include +#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/miniupnpc/connecthostport.h b/ext/miniupnpc/connecthostport.h new file mode 100644 index 00000000..56941d6f --- /dev/null +++ b/ext/miniupnpc/connecthostport.h @@ -0,0 +1,18 @@ +/* $Id: connecthostport.h,v 1.3 2012/09/27 15:42:10 nanard Exp $ */ +/* Project: miniupnp + * http://miniupnp.free.fr/ + * Author: Thomas Bernard + * Copyright (c) 2010-2012 Thomas Bernard + * This software is subjects to the conditions detailed + * in the LICENCE file provided within this distribution */ +#ifndef CONNECTHOSTPORT_H_INCLUDED +#define CONNECTHOSTPORT_H_INCLUDED + +/* 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); + +#endif + 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 +#include + +/* 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/miniupnpc/igd_desc_parse.h b/ext/miniupnpc/igd_desc_parse.h new file mode 100644 index 00000000..0de546b6 --- /dev/null +++ b/ext/miniupnpc/igd_desc_parse.h @@ -0,0 +1,49 @@ +/* $Id: igd_desc_parse.h,v 1.12 2014/11/17 17:19:13 nanard Exp $ */ +/* Project : miniupnp + * http://miniupnp.free.fr/ + * Author : Thomas Bernard + * Copyright (c) 2005-2014 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. + * */ +#ifndef IGD_DESC_PARSE_H_INCLUDED +#define IGD_DESC_PARSE_H_INCLUDED + +/* Structure to store the result of the parsing of UPnP + * descriptions of Internet Gateway Devices */ +#define MINIUPNPC_URL_MAXSIZE (128) +struct IGDdatas_service { + char controlurl[MINIUPNPC_URL_MAXSIZE]; + char eventsuburl[MINIUPNPC_URL_MAXSIZE]; + char scpdurl[MINIUPNPC_URL_MAXSIZE]; + char servicetype[MINIUPNPC_URL_MAXSIZE]; + /*char devicetype[MINIUPNPC_URL_MAXSIZE];*/ +}; + +struct IGDdatas { + char cureltname[MINIUPNPC_URL_MAXSIZE]; + char urlbase[MINIUPNPC_URL_MAXSIZE]; + char presentationurl[MINIUPNPC_URL_MAXSIZE]; + int level; + /*int state;*/ + /* "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" */ + struct IGDdatas_service CIF; + /* "urn:schemas-upnp-org:service:WANIPConnection:1" + * "urn:schemas-upnp-org:service:WANPPPConnection:1" */ + struct IGDdatas_service first; + /* if both WANIPConnection and WANPPPConnection are present */ + struct IGDdatas_service second; + /* "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1" */ + struct IGDdatas_service IPv6FC; + /* tmp */ + struct IGDdatas_service tmp; +}; + +void IGDstartelt(void *, const char *, int); +void IGDendelt(void *, const char *, int); +void IGDdata(void *, const char *, int); +#ifdef DEBUG +void printIGD(struct IGDdatas *); +#endif /* DEBUG */ + +#endif /* IGD_DESC_PARSE_H_INCLUDED */ 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 +#include +#include +#ifdef _WIN32 +#include +#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 ...]\n", argv[0]); + printf("options :\n"); + printf(" -6 : use IPv6\n"); + printf(" -m address/ifname : network interface to use for multicast\n"); + printf(" -d : search only for this type of device\n"); + printf(" -l ... : 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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..0b56558e --- /dev/null +++ b/ext/miniupnpc/minisoap.c @@ -0,0 +1,123 @@ +/* $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 +#include +#ifdef _WIN32 +#include +#include +#define snprintf _snprintf +#else +#include +#include +#include +#endif +#include "minisoap.h" +#include "miniupnpcstrings.h" + +/* only for malloc */ +#include + +#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/miniupnpc/minisoap.h b/ext/miniupnpc/minisoap.h new file mode 100644 index 00000000..14c859d1 --- /dev/null +++ b/ext/miniupnpc/minisoap.h @@ -0,0 +1,15 @@ +/* $Id: minisoap.h,v 1.5 2012/09/27 15:42:10 nanard Exp $ */ +/* Project : miniupnp + * Author : Thomas Bernard + * Copyright (c) 2005 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. */ +#ifndef MINISOAP_H_INCLUDED +#define MINISOAP_H_INCLUDED + +/*int httpWrite(int, const char *, int, const char *);*/ +int soapPostSubmit(int, const char *, const char *, unsigned short, + const char *, const char *, const char *); + +#endif + diff --git a/ext/miniupnpc/minissdpc.c b/ext/miniupnpc/minissdpc.c new file mode 100644 index 00000000..5a426739 --- /dev/null +++ b/ext/miniupnpc/minissdpc.c @@ -0,0 +1,849 @@ +/* $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 */ +#include +#include +#include +#include +#if defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__) +#ifdef _WIN32 +#include +#include +#include +#include +#include +#define snprintf _snprintf +#if !defined(_MSC_VER) +#include +#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 +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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(isin6_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..4837fe7d --- /dev/null +++ b/ext/miniupnpc/miniupnpc.c @@ -0,0 +1,684 @@ +/* $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 +#include +#include +#ifdef _WIN32 +/* Win32 Specific includes and defines */ +#include +#include +#include +#include +#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 +#if defined(__amigaos__) && !defined(__amigaos4__) +/* Amiga OS 3 specific stuff */ +#define socklen_t int +#else +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#if !defined(__amigaos__) && !defined(__amigaos4__) +#include +#endif +#include +#include +#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), + "\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\">" + "" + "" + "\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), + "\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, ">\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 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/miniupnpc/miniupnpc.h b/ext/miniupnpc/miniupnpc.h new file mode 100644 index 00000000..dfbfa01f --- /dev/null +++ b/ext/miniupnpc/miniupnpc.h @@ -0,0 +1,152 @@ +/* $Id: miniupnpc.h,v 1.48 2015/10/08 16:19:40 nanard Exp $ */ +/* Project: miniupnp + * http://miniupnp.free.fr/ + * 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 MINIUPNPC_H_INCLUDED +#define MINIUPNPC_H_INCLUDED + +#include "miniupnpc_declspec.h" +#include "igd_desc_parse.h" +#include "upnpdev.h" + +/* error codes : */ +#define UPNPDISCOVER_SUCCESS (0) +#define UPNPDISCOVER_UNKNOWN_ERROR (-1) +#define UPNPDISCOVER_SOCKET_ERROR (-101) +#define UPNPDISCOVER_MEMORY_ERROR (-102) + +/* versions : */ +#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" { +#endif + +/* Structures definitions : */ +struct UPNParg { const char * elt; const char * val; }; + +char * +simpleUPnPcommand(int, const char *, const char *, + const char *, struct UPNParg *, + int *); + +/* upnpDiscover() + * discover UPnP devices on the network. + * The discovered devices are returned as a chained list. + * It is up to the caller to free the list with freeUPNPDevlist(). + * 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. + * "searchalltypes" parameter is useful when searching several types, + * 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 localport, + int ipv6, unsigned char ttl, + int * error); + +MINIUPNP_LIBSPEC struct UPNPDev * +upnpDiscoverAll(int delay, const char * multicastif, + 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 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 localport, + int ipv6, unsigned char ttl, + int * error, + int searchalltypes); + +/* parserootdesc() : + * parse root XML description of a UPnP device and fill the IGDdatas + * structure. */ +MINIUPNP_LIBSPEC void parserootdesc(const char *, int, struct IGDdatas *); + +/* structure used to get fast access to urls + * controlURL: controlURL of the WANIPConnection + * ipcondescURL: url of the description of the WANIPConnection + * controlURL_CIF: controlURL of the WANCommonInterfaceConfig + * controlURL_6FC: controlURL of the WANIPv6FirewallControl + */ +struct UPNPUrls { + char * controlURL; + char * ipcondescURL; + char * controlURL_CIF; + char * controlURL_6FC; + char * rootdescURL; +}; + +/* UPNP_GetValidIGD() : + * return values : + * 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 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); + +/* UPNP_GetIGDFromUrl() + * Used when skipping the discovery process. + * When succeding, urls, data, and lanaddr arguments are set. + * return value : + * 0 - Not ok + * 1 - OK */ +MINIUPNP_LIBSPEC int +UPNP_GetIGDFromUrl(const char * rootdescurl, + struct UPNPUrls * urls, + struct IGDdatas * data, + char * lanaddr, int lanaddrlen); + +MINIUPNP_LIBSPEC void +GetUPNPUrls(struct UPNPUrls *, struct IGDdatas *, + const char *, unsigned int); + +MINIUPNP_LIBSPEC void +FreeUPNPUrls(struct UPNPUrls *); + +/* return 0 or 1 */ +MINIUPNP_LIBSPEC int UPNPIGD_IsConnected(struct UPNPUrls *, struct IGDdatas *); + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/ext/miniupnpc/miniupnpc_declspec.h b/ext/miniupnpc/miniupnpc_declspec.h new file mode 100644 index 00000000..40adb922 --- /dev/null +++ b/ext/miniupnpc/miniupnpc_declspec.h @@ -0,0 +1,21 @@ +#ifndef MINIUPNPC_DECLSPEC_H_INCLUDED +#define MINIUPNPC_DECLSPEC_H_INCLUDED + +#if defined(_WIN32) && !defined(MINIUPNP_STATICLIB) + /* for windows dll */ + #ifdef MINIUPNP_EXPORTS + #define MINIUPNP_LIBSPEC __declspec(dllexport) + #else + #define MINIUPNP_LIBSPEC __declspec(dllimport) + #endif +#else + #if defined(__GNUC__) && __GNUC__ >= 4 + /* fix dynlib for OS X 10.9.2 and Apple LLVM version 5.0 */ + #define MINIUPNP_LIBSPEC __attribute__ ((visibility ("default"))) + #else + #define MINIUPNP_LIBSPEC + #endif +#endif + +#endif /* MINIUPNPC_DECLSPEC_H_INCLUDED */ + 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 +#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/miniupnpc/miniupnpcstrings.h.in b/ext/miniupnpc/miniupnpcstrings.h.in new file mode 100644 index 00000000..68bf4293 --- /dev/null +++ b/ext/miniupnpc/miniupnpcstrings.h.in @@ -0,0 +1,23 @@ +/* $Id: miniupnpcstrings.h.in,v 1.6 2014/11/04 22:31:55 nanard Exp $ */ +/* Project: miniupnp + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * Author: Thomas Bernard + * Copyright (c) 2005-2014 Thomas Bernard + * This software is subjects to the conditions detailed + * in the LICENCE file provided within this distribution */ +#ifndef MINIUPNPCSTRINGS_H_INCLUDED +#define MINIUPNPCSTRINGS_H_INCLUDED + +#define OS_STRING "OS/version" +#define MINIUPNPC_VERSION_STRING "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/miniupnpc/miniupnpctypes.h b/ext/miniupnpc/miniupnpctypes.h new file mode 100644 index 00000000..591c32fb --- /dev/null +++ b/ext/miniupnpc/miniupnpctypes.h @@ -0,0 +1,19 @@ +/* $Id: miniupnpctypes.h,v 1.2 2012/09/27 15:42:10 nanard Exp $ */ +/* Miniupnp project : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org + * Author : Thomas Bernard + * Copyright (c) 2011 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided within this distribution */ +#ifndef MINIUPNPCTYPES_H_INCLUDED +#define MINIUPNPCTYPES_H_INCLUDED + +#if (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L) +#define UNSIGNED_INTEGER unsigned long long +#define STRTOUI strtoull +#else +#define UNSIGNED_INTEGER unsigned int +#define STRTOUI strtoul +#endif + +#endif + diff --git a/ext/miniupnpc/miniwget.c b/ext/miniupnpc/miniwget.c new file mode 100644 index 00000000..40aa7180 --- /dev/null +++ b/ext/miniupnpc/miniwget.c @@ -0,0 +1,626 @@ +/* $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 +#include +#include +#include +#ifdef _WIN32 +#include +#include +#include +#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 +#include +#if defined(__amigaos__) && !defined(__amigaos4__) +#define socklen_t int +#else /* #if defined(__amigaos__) && !defined(__amigaos4__) */ +#include +#endif /* #else defined(__amigaos__) && !defined(__amigaos4__) */ +#include +#include +#include +#include +#include +#define closesocket close +#include +#endif /* #else _WIN32 */ +#ifdef __GNU__ +#define MAXHOSTNAMELEN 64 +#endif /* __GNU__ */ + +#ifndef MIN +#define MIN(x,y) (((x)<(y))?(x):(y)) +#endif /* MIN */ + + +#include "miniupnpcstrings.h" +#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= '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/miniupnpc/miniwget.h b/ext/miniupnpc/miniwget.h new file mode 100644 index 00000000..d6db71a8 --- /dev/null +++ b/ext/miniupnpc/miniwget.h @@ -0,0 +1,30 @@ +/* $Id: miniwget.h,v 1.10 2015/07/21 13:16:55 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. + * */ +#ifndef MINIWGET_H_INCLUDED +#define MINIWGET_H_INCLUDED + +#include "miniupnpc_declspec.h" + +#ifdef __cplusplus +extern "C" { +#endif + +MINIUPNP_LIBSPEC void * getHTTPResponse(int s, int * size); + +MINIUPNP_LIBSPEC void * miniwget(const char *, int *, unsigned int); + +MINIUPNP_LIBSPEC void * miniwget_getaddr(const char *, int *, char *, int, unsigned int); + +int parseURL(const char *, char *, unsigned short *, char * *, unsigned int *); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/ext/miniupnpc/minixml.c b/ext/miniupnpc/minixml.c new file mode 100644 index 00000000..3e201ec2 --- /dev/null +++ b/ext/miniupnpc/minixml.c @@ -0,0 +1,229 @@ +/* $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 +#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, "", 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, "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/miniupnpc/minixml.h b/ext/miniupnpc/minixml.h new file mode 100644 index 00000000..9f43aa48 --- /dev/null +++ b/ext/miniupnpc/minixml.h @@ -0,0 +1,37 @@ +/* $Id: minixml.h,v 1.7 2012/09/27 15:42:10 nanard Exp $ */ +/* minimal xml parser + * + * Project : miniupnp + * Website : http://miniupnp.free.fr/ + * Author : Thomas Bernard + * Copyright (c) 2005 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. + * */ +#ifndef MINIXML_H_INCLUDED +#define MINIXML_H_INCLUDED +#define IS_WHITE_SPACE(c) ((c==' ') || (c=='\t') || (c=='\r') || (c=='\n')) + +/* if a callback function pointer is set to NULL, + * the function is not called */ +struct xmlparser { + const char *xmlstart; + const char *xmlend; + const char *xml; /* pointer to current character */ + int xmlsize; + void * data; + void (*starteltfunc) (void *, const char *, int); + void (*endeltfunc) (void *, const char *, int); + void (*datafunc) (void *, const char *, int); + void (*attfunc) (void *, const char *, int, const char *, int); +}; + +/* parsexml() + * the xmlparser structure must be initialized before the call + * the following structure members have to be initialized : + * xmlstart, xmlsize, data, *func + * xml is for internal usage, xmlend is computed automatically */ +void parsexml(struct xmlparser *); + +#endif + diff --git a/ext/miniupnpc/minixmlvalid.c b/ext/miniupnpc/minixmlvalid.c new file mode 100644 index 00000000..dad14881 --- /dev/null +++ b/ext/miniupnpc/minixmlvalid.c @@ -0,0 +1,163 @@ +/* $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 +#include +#include +#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; in; 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[] = +"\n" +" " +"character data" +" \n \t" +"" +"\nstuff !\n ]]> \n\n" +" \tchardata1 chardata2 " +""; + +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, " 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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 +#include +#ifdef DEBUG +#include +#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/miniupnpc/portlistingparse.h b/ext/miniupnpc/portlistingparse.h new file mode 100644 index 00000000..661ad1fa --- /dev/null +++ b/ext/miniupnpc/portlistingparse.h @@ -0,0 +1,65 @@ +/* $Id: portlistingparse.h,v 1.11 2015/07/21 13:16:55 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 */ +#ifndef PORTLISTINGPARSE_H_INCLUDED +#define PORTLISTINGPARSE_H_INCLUDED + +#include "miniupnpc_declspec.h" +/* for the definition of UNSIGNED_INTEGER */ +#include "miniupnpctypes.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* sample of PortMappingEntry : + + 202.233.2.1 + 2345 + TCP + 2345 + 192.168.1.137 + 1 + dooom + 345 + + */ +typedef enum { PortMappingEltNone, + PortMappingEntry, NewRemoteHost, + NewExternalPort, NewProtocol, + NewInternalPort, NewInternalClient, + NewEnabled, NewDescription, + NewLeaseTime } portMappingElt; + +struct PortMapping { + struct PortMapping * l_next; /* list next element */ + UNSIGNED_INTEGER leaseTime; + unsigned short externalPort; + unsigned short internalPort; + char remoteHost[64]; + char internalClient[64]; + char description[64]; + char protocol[4]; + unsigned char enabled; +}; + +struct PortMappingParserData { + struct PortMapping * l_head; /* list head */ + portMappingElt curelt; +}; + +MINIUPNP_LIBSPEC void +ParsePortListing(const char * buffer, int bufsize, + struct PortMappingParserData * pdata); + +MINIUPNP_LIBSPEC void +FreePortListing(struct PortMappingParserData * pdata); + +#ifdef __cplusplus +} +#endif + +#endif 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 +#include +#ifdef _WIN32 +#include +#include +#else /* _WIN32 */ +#include +#if defined(__amigaos__) && !defined(__amigaos4__) +#define socklen_t int +#else /* #if defined(__amigaos__) && !defined(__amigaos4__) */ +#include +#endif /* #else defined(__amigaos__) && !defined(__amigaos4__) */ +#include +#include +#if !defined(__amigaos__) && !defined(__amigaos4__) +#include +#endif /* !defined(__amigaos__) && !defined(__amigaos4__) */ +#include +#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/miniupnpc/receivedata.h b/ext/miniupnpc/receivedata.h new file mode 100644 index 00000000..0520a11d --- /dev/null +++ b/ext/miniupnpc/receivedata.h @@ -0,0 +1,19 @@ +/* $Id: receivedata.h,v 1.4 2012/09/27 15:42:10 nanard Exp $ */ +/* Project: miniupnp + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * Author: Thomas Bernard + * Copyright (c) 2011-2012 Thomas Bernard + * This software is subjects to the conditions detailed + * in the LICENCE file provided within this distribution */ +#ifndef RECEIVEDATA_H_INCLUDED +#define RECEIVEDATA_H_INCLUDED + +/* Reads data from the specified socket. + * Returns the number of bytes read if successful, zero if no bytes were + * read or if we timed out. Returns negative if there was an error. */ +int receivedata(int socket, + char * data, int length, + int timeout, unsigned int * scope_id); + +#endif + 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 @@ + + + +1 +0 + +http://192.168.1.1:49152 + +urn:schemas-upnp-org:device:InternetGatewayDevice:1 +LINKSYS WAG200G Gateway +LINKSYS +http://www.linksys.com +LINKSYS WAG200G Gateway +Wireless-G ADSL Home Gateway +WAG200G +http://www.linksys.com +123456789 +uuid:8ca2eb37-1dd2-11b2-86f1-001a709b5aa8 +WAG200G + + +urn:schemas-upnp-org:service:Layer3Forwarding:1 +urn:upnp-org:serviceId:L3Forwarding1 +/upnp/control/L3Forwarding1 +/upnp/event/L3Forwarding1 +/l3frwd.xml + + + + +urn:schemas-upnp-org:device:WANDevice:1 +WANDevice +LINKSYS +http://www.linksys.com/ +Residential Gateway +Internet Connection Sharing +1 +http://www.linksys.com/ +0000001 +uuid:8ca2eb36-1dd2-11b2-86f1-001a709b5aa8 +WAG200G + + +urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1 +urn:upnp-org:serviceId:WANCommonIFC1 +/upnp/control/WANCommonIFC1 +/upnp/event/WANCommonIFC1 +/cmnicfg.xml + + + + +urn:schemas-upnp-org:device:WANConnectionDevice:1 +WANConnectionDevice +LINKSYS +http://www.linksys.com/ +Residential Gateway +Internet Connection Sharing +1 +http://www.linksys.com/ +0000001 +uuid:8ca2eb37-1dd2-11b2-86f0-001a709b5aa8 +WAG200G + + +urn:schemas-upnp-org:service:WANEthernetLinkConfig:1 +urn:upnp-org:serviceId:WANEthLinkC1 +/upnp/control/WANEthLinkC1 +/upnp/event/WANEthLinkC1 +/wanelcfg.xml + + +urn:schemas-upnp-org:service:WANPPPConnection:1 +urn:upnp-org:serviceId:WANPPPConn1 +/upnp/control/WANPPPConn1 +/upnp/event/WANPPPConn1 +/pppcfg.xml + + + + + + +urn:schemas-upnp-org:device:LANDevice:1 +LANDevice +LINKSYS +http://www.linksys.com/ +Residential Gateway +Residential Gateway +1 +http://www.linksys.com/ +0000001 +uuid:8ca2eb36-1dd2-11b2-86f0-001a709b5aa +8 +WAG200G + + +urn:schemas-upnp-org:service:LANHostConfigManagement:1 +urn:upnp-org:serviceId:LANHostCfg1 +/upnp/control/LANHostCfg1 +/upnp/event/LANHostCfg1 +/lanhostc.xml + + + + +http://192.168.1.1/index.htm + + + 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 @@ + + + + 1 + 0 + + + VEN_0129&DEV_0000&SUBSYS_03&REV_250417 + GenericUmPass + NetworkInfrastructure.Gateway + Network.Gateway + urn:schemas-upnp-org:device:InternetGatewayDevice:2 + Orange Livebox + Sagemcom + http://www.sagemcom.com/ + Residential Livebox,(DSL,WAN Ethernet) + uuid:87895a19-50f9-3736-a87f-115c230155f8 + Sagemcom,fr,SG30_sip-fr-4.28.35.1 + 3 + LK14129DP441489 + http://192.168.1.1 + + + + image/png + 16 + 16 + 8 + /87895a19/ligd.png + + + + + urn:schemas-upnp-org:device:WANDevice:2 + WANDevice + Sagemcom + http://www.sagemcom.com/ + WAN Device on Sagemcom,fr,SG30_sip-fr-4.28.35.1 + Residential Livebox,(DSL,WAN Ethernet) + 3 + http://www.sagemcom.com/ + LK14129DP441489 + http://192.168.1.1 + uuid:e2397374-53d8-3fc6-8306-593ba1a34625 + + + + urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1 + urn:upnp-org:serviceId:WANCommonIFC1 + /87895a19/upnp/control/WANCommonIFC1 + /87895a19/upnp/control/WANCommonIFC1 + /87895a19/gateicfgSCPD.xml + + + + + urn:schemas-upnp-org:device:WANConnectionDevice:2 + WANConnectionDevice + Sagemcom + http://www.sagemcom.com/ + WanConnectionDevice on Sagemcom,fr,SG30_sip-fr-4.28.35.1 + Residential Livebox,(DSL,WAN Ethernet) + 3 + http://www.sagemcom.com/ + LK14129DP441489 + http://192.168.1.1 + uuid:44598a08-288e-32c9-8a4d-d3c008ede331 + + + + urn:schemas-upnp-org:service:WANPPPConnection:2 + urn:upnp-org:serviceId:WANIPConn1 + /87895a19/upnp/control/WANIPConn1 + /87895a19/upnp/control/WANIPConn1 + /87895a19/gateconnSCPD_PPP.xml + + + urn:schemas-upnp-org:service:WANIPv6FirewallControl:1 + urn:upnp-org:serviceId:WANIPv6FwCtrl1 + /87895a19/upnp/control/WANIPv6FwCtrl1 + /87895a19/upnp/control/WANIPv6FwCtrl1 + /87895a19/wanipv6fwctrlSCPD.xml + + + + + + + + \ 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 +#include +#include +#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 +#include +#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 +#include +#include +#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 +#include +#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[] = +"\n" +"\n" +" \n" +" \n" +" 5002\n" +" UDP\n" +" 4001\n" +" 192.168.1.123\n" +" 1\n" +" xxx\n" +" 0\n" +" \n" +" \n" +" 202.233.2.1\n" +" 2345\n" +" TCP\n" +" 2349\n" +" 192.168.1.137\n" +" 1\n" +" dooom\n" +" 346\n" +" \n" +" \n" +" 134.231.2.11\n" +" 12345\n" +" TCP\n" +" 12345\n" +" 192.168.1.137\n" +" 1\n" +" dooom A\n" +" 347\n" +" \n" +""; + +#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 @@ + +123 +TCP + + + 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 @@ +1.2.3.4 + 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 @@ + +12345UDP + 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 @@ +12345192.168.10.1101libminiupnpc0 + 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 @@ +uuid:c6c05a33-f704-48df-9910-e099b3471d81:WANConnectionDevice:1,INVALID_SERVICE_ID 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 +#include +#include +#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 : ""); + 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 +#include +#include +#include +#ifdef _WIN32 +#include +#define snprintf _snprintf +#else +/* for IPPROTO_TCP / IPPROTO_UDP */ +#include +#endif +#include +#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(×tarted)); + 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; i65535 || + (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 \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 */ + 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 : */ + 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 +#include +#include +#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/miniupnpc/upnpcommands.h b/ext/miniupnpc/upnpcommands.h new file mode 100644 index 00000000..22eda5e3 --- /dev/null +++ b/ext/miniupnpc/upnpcommands.h @@ -0,0 +1,348 @@ +/* $Id: upnpcommands.h,v 1.31 2015/07/21 13:16:55 nanard Exp $ */ +/* Miniupnp project : 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 within this distribution */ +#ifndef UPNPCOMMANDS_H_INCLUDED +#define UPNPCOMMANDS_H_INCLUDED + +#include "upnpreplyparse.h" +#include "portlistingparse.h" +#include "miniupnpc_declspec.h" +#include "miniupnpctypes.h" + +/* MiniUPnPc return codes : */ +#define UPNPCOMMAND_SUCCESS (0) +#define UPNPCOMMAND_UNKNOWN_ERROR (-1) +#define UPNPCOMMAND_INVALID_ARGS (-2) +#define UPNPCOMMAND_HTTP_ERROR (-3) +#define UPNPCOMMAND_INVALID_RESPONSE (-4) +#define UPNPCOMMAND_MEM_ALLOC_ERROR (-5) + +#ifdef __cplusplus +extern "C" { +#endif + +MINIUPNP_LIBSPEC UNSIGNED_INTEGER +UPNP_GetTotalBytesSent(const char * controlURL, + const char * servicetype); + +MINIUPNP_LIBSPEC UNSIGNED_INTEGER +UPNP_GetTotalBytesReceived(const char * controlURL, + const char * servicetype); + +MINIUPNP_LIBSPEC UNSIGNED_INTEGER +UPNP_GetTotalPacketsSent(const char * controlURL, + const char * servicetype); + +MINIUPNP_LIBSPEC UNSIGNED_INTEGER +UPNP_GetTotalPacketsReceived(const char * controlURL, + const char * servicetype); + +/* UPNP_GetStatusInfo() + * status and lastconnerror are 64 byte buffers + * Return values : + * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR + * or a UPnP Error code */ +MINIUPNP_LIBSPEC int +UPNP_GetStatusInfo(const char * controlURL, + const char * servicetype, + char * status, + unsigned int * uptime, + char * lastconnerror); + +/* UPNP_GetConnectionTypeInfo() + * argument connectionType is a 64 character buffer + * Return Values : + * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR + * or a UPnP Error code */ +MINIUPNP_LIBSPEC int +UPNP_GetConnectionTypeInfo(const char * controlURL, + const char * servicetype, + char * connectionType); + +/* 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. + * + * possible UPnP Errors : + * 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); + +/* UPNP_GetLinkLayerMaxBitRates() + * call WANCommonInterfaceConfig:1#GetCommonLinkProperties + * + * return values : + * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR + * or a UPnP Error Code. */ +MINIUPNP_LIBSPEC int +UPNP_GetLinkLayerMaxBitRates(const char* controlURL, + const char* servicetype, + unsigned int * bitrateDown, + unsigned int * bitrateUp); + +/* UPNP_AddPortMapping() + * if desc is NULL, it will be defaulted to "libminiupnpc" + * remoteHost is usually NULL because IGD don't support it. + * + * Return values : + * 0 : SUCCESS + * NON ZERO : ERROR. Either an UPnP error code or an unknown error. + * + * List of possible UPnP errors for AddPortMapping : + * errorCode errorDescription (short) - Description (long) + * 402 Invalid Args - See UPnP Device Architecture section on Control. + * 501 Action Failed - See UPnP Device Architecture section on Control. + * 606 Action not authorized - The action requested REQUIRES authorization and + * the sender was not authorized. + * 715 WildCardNotPermittedInSrcIP - The source IP address cannot be + * wild-carded + * 716 WildCardNotPermittedInExtPort - The external port cannot be wild-carded + * 718 ConflictInMappingEntry - The port mapping entry specified conflicts + * with a mapping assigned previously to another client + * 724 SamePortValuesRequired - Internal and External port values + * must be the same + * 725 OnlyPermanentLeasesSupported - The NAT implementation only supports + * permanent lease times on port mappings + * 726 RemoteHostOnlySupportsWildcard - RemoteHost must be a wildcard + * and cannot be a specific IP address or DNS name + * 727 ExternalPortOnlySupportsWildcard - ExternalPort must be a wildcard and + * cannot be a specific port value + * 728 NoPortMapsAvailable - There are not enough free ports available to + * complete port mapping. + * 729 ConflictWithOtherMechanisms - Attempted port mapping is not allowed + * due to conflict with other mechanisms. + * 732 WildCardNotPermittedInIntPort - The internal port cannot be wild-carded + */ +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); + +/* UPNP_AddAnyPortMapping() + * if desc is NULL, it will be defaulted to "libminiupnpc" + * remoteHost is usually NULL because IGD don't support it. + * + * Return values : + * 0 : SUCCESS + * NON ZERO : ERROR. Either an UPnP error code or an unknown error. + * + * List of possible UPnP errors for AddPortMapping : + * errorCode errorDescription (short) - Description (long) + * 402 Invalid Args - See UPnP Device Architecture section on Control. + * 501 Action Failed - See UPnP Device Architecture section on Control. + * 606 Action not authorized - The action requested REQUIRES authorization and + * the sender was not authorized. + * 715 WildCardNotPermittedInSrcIP - The source IP address cannot be + * wild-carded + * 716 WildCardNotPermittedInExtPort - The external port cannot be wild-carded + * 728 NoPortMapsAvailable - There are not enough free ports available to + * complete port mapping. + * 729 ConflictWithOtherMechanisms - Attempted port mapping is not allowed + * due to conflict with other mechanisms. + * 732 WildCardNotPermittedInIntPort - The internal port cannot be wild-carded + */ +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); + +/* UPNP_DeletePortMapping() + * Use same argument values as what was used for AddPortMapping(). + * remoteHost is usually NULL because IGD don't support it. + * Return Values : + * 0 : SUCCESS + * NON ZERO : error. Either an UPnP error code or an undefined error. + * + * List of possible UPnP errors for DeletePortMapping : + * 402 Invalid Args - See UPnP Device Architecture section on Control. + * 606 Action not authorized - The action requested REQUIRES authorization + * and the sender was not authorized. + * 714 NoSuchEntryInArray - The specified value does not exist in the array */ +MINIUPNP_LIBSPEC int +UPNP_DeletePortMapping(const char * controlURL, const char * servicetype, + const char * extPort, const char * proto, + const char * remoteHost); + +/* UPNP_DeletePortRangeMapping() + * Use same argument values as what was used for AddPortMapping(). + * remoteHost is usually NULL because IGD don't support it. + * Return Values : + * 0 : SUCCESS + * NON ZERO : error. Either an UPnP error code or an undefined error. + * + * List of possible UPnP errors for DeletePortMapping : + * 606 Action not authorized - The action requested REQUIRES authorization + * and the sender was not authorized. + * 730 PortMappingNotFound - This error message is returned if no port + * mapping is found in the specified range. + * 733 InconsistentParameters - NewStartPort and NewEndPort values are not consistent. */ +MINIUPNP_LIBSPEC int +UPNP_DeletePortMappingRange(const char * controlURL, const char * servicetype, + const char * extPortStart, const char * extPortEnd, + const char * proto, + const char * manage); + +/* UPNP_GetPortMappingNumberOfEntries() + * not supported by all routers */ +MINIUPNP_LIBSPEC int +UPNP_GetPortMappingNumberOfEntries(const char* controlURL, + const char* servicetype, + unsigned int * num); + +/* UPNP_GetSpecificPortMappingEntry() + * retrieves an existing port mapping + * params : + * in extPort + * in proto + * in remoteHost + * out intClient (16 bytes) + * out intPort (6 bytes) + * out desc (80 bytes) + * out enabled (4 bytes) + * out leaseDuration (16 bytes) + * + * return value : + * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR + * or a UPnP Error Code. + * + * List of possible UPnP errors for _GetSpecificPortMappingEntry : + * 402 Invalid Args - See UPnP Device Architecture section on Control. + * 501 Action Failed - See UPnP Device Architecture section on Control. + * 606 Action not authorized - The action requested REQUIRES authorization + * and the sender was not authorized. + * 714 NoSuchEntryInArray - The specified value does not exist in the array. + */ +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); + +/* UPNP_GetGenericPortMappingEntry() + * params : + * in index + * out extPort (6 bytes) + * out intClient (16 bytes) + * out intPort (6 bytes) + * out protocol (4 bytes) + * out desc (80 bytes) + * out enabled (4 bytes) + * out rHost (64 bytes) + * out duration (16 bytes) + * + * return value : + * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR + * or a UPnP Error Code. + * + * Possible UPNP Error codes : + * 402 Invalid Args - See UPnP Device Architecture section on Control. + * 606 Action not authorized - The action requested REQUIRES authorization + * and the sender was not authorized. + * 713 SpecifiedArrayIndexInvalid - The specified array index is out of bounds + */ +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); + +/* UPNP_GetListOfPortMappings() Available in IGD v2 + * + * + * 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); + +/* IGD:2, functions for service WANIPv6FirewallControl:1 */ +MINIUPNP_LIBSPEC int +UPNP_GetFirewallStatus(const char * controlURL, + const char * servicetype, + int * firewallEnabled, + int * inboundPinholeAllowed); + +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); + +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); + +MINIUPNP_LIBSPEC int +UPNP_UpdatePinhole(const char * controlURL, const char * servicetype, + const char * uniqueID, + const char * leaseTime); + +MINIUPNP_LIBSPEC int +UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char * uniqueID); + +MINIUPNP_LIBSPEC int +UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype, + const char * uniqueID, int * isWorking); + +MINIUPNP_LIBSPEC int +UPNP_GetPinholePackets(const char * controlURL, const char * servicetype, + const char * uniqueID, int * packets); + +#ifdef __cplusplus +} +#endif + +#endif + 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 +#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 +#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/miniupnpc/upnperrors.h b/ext/miniupnpc/upnperrors.h new file mode 100644 index 00000000..3115aee5 --- /dev/null +++ b/ext/miniupnpc/upnperrors.h @@ -0,0 +1,26 @@ +/* $Id: upnperrors.h,v 1.6 2015/07/21 13:16:55 nanard Exp $ */ +/* (c) 2007-2015 Thomas Bernard + * All rights reserved. + * MiniUPnP Project. + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * This software is subjet to the conditions detailed in the + * provided LICENCE file. */ +#ifndef UPNPERRORS_H_INCLUDED +#define UPNPERRORS_H_INCLUDED + +#include "miniupnpc_declspec.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* strupnperror() + * Return a string description of the UPnP error code + * or NULL for undefinded errors */ +MINIUPNP_LIBSPEC const char * strupnperror(int err); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ext/miniupnpc/upnpreplyparse.c b/ext/miniupnpc/upnpreplyparse.c new file mode 100644 index 00000000..5de5796a --- /dev/null +++ b/ext/miniupnpc/upnpreplyparse.c @@ -0,0 +1,197 @@ +/* $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 +#include +#include + +#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/miniupnpc/upnpreplyparse.h b/ext/miniupnpc/upnpreplyparse.h new file mode 100644 index 00000000..6badd15b --- /dev/null +++ b/ext/miniupnpc/upnpreplyparse.h @@ -0,0 +1,63 @@ +/* $Id: upnpreplyparse.h,v 1.19 2014/10/27 16:33:19 nanard Exp $ */ +/* MiniUPnP project + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * (c) 2006-2013 Thomas Bernard + * This software is subject to the conditions detailed + * in the LICENCE file provided within the distribution */ + +#ifndef UPNPREPLYPARSE_H_INCLUDED +#define UPNPREPLYPARSE_H_INCLUDED + +#ifdef __cplusplus +extern "C" { +#endif + +struct NameValue { + struct NameValue * l_next; + char name[64]; + char value[128]; +}; + +struct NameValueParserData { + struct NameValue * l_head; + char curelt[64]; + char * portListing; + int portListingLength; + int topelt; + const char * cdata; + int cdatalen; +}; + +/* ParseNameValue() */ +void +ParseNameValue(const char * buffer, int bufsize, + struct NameValueParserData * data); + +/* ClearNameValueList() */ +void +ClearNameValueList(struct NameValueParserData * pdata); + +/* GetValueFromNameValueList() */ +char * +GetValueFromNameValueList(struct NameValueParserData * pdata, + const char * Name); + +#if 0 +/* GetValueFromNameValueListIgnoreNS() */ +char * +GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata, + const char * Name); +#endif + +/* DisplayNameValueList() */ +#ifdef DEBUG +void +DisplayNameValueList(char * buffer, int bufsize); +#endif + +#ifdef __cplusplus +} +#endif + +#endif + 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 +#include + +/* 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/make-mac.mk b/make-mac.mk index 6ea23859..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 @@ -34,7 +34,7 @@ endif # Build with ZT_ENABLE_CLUSTER=1 to build with cluster support ifeq ($(ZT_ENABLE_CLUSTER),1) - DEFS+=-DZT_ENABLE_CLUSTER + DEFS+=-DZT_ENABLE_CLUSTER endif ifeq ($(ZT_AUTO_UPDATE),1) @@ -43,7 +43,7 @@ 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 @@ -73,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 @@ -99,6 +102,7 @@ official: FORCE 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-* mkworld + cd ext/miniupnpc ; make clean # For those building from source -- installs signed binary tap driver in system ZT home install-mac-tap: FORCE -- cgit v1.2.3 From dc8edea0c62a39b147c12a037f42df3cabc232c4 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 16 Nov 2015 18:33:52 -0800 Subject: Linux make rules to make libminiupnpc from source. --- make-linux.mk | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/make-linux.mk b/make-linux.mk index 339b548d..d4414e38 100644 --- a/make-linux.mk +++ b/make-linux.mk @@ -43,23 +43,7 @@ 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 @@ -106,6 +90,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 @@ -120,6 +107,7 @@ installer: one FORCE clean: rm -rf *.o 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 + cd ext/miniupnpc ; make clean debug: FORCE make ZT_DEBUG=1 one -- cgit v1.2.3 From 0f5fb48a0ba70ced52aa69ca7ff00824cf8fb829 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 16 Nov 2015 19:04:04 -0800 Subject: Turns out it wasn't hard to add miniupnpc to the VS2012 project and just have it build with the rest of the code. --- ext/bin/miniupnpc/Changelog.txt | 633 --------------------- ext/bin/miniupnpc/LICENSE | 27 - ext/bin/miniupnpc/README.md | 4 - ext/bin/miniupnpc/VERSION | 1 - ext/bin/miniupnpc/include/miniupnpc/codelength.h | 54 -- .../miniupnpc/include/miniupnpc/connecthostport.h | 18 - .../miniupnpc/include/miniupnpc/igd_desc_parse.h | 49 -- ext/bin/miniupnpc/include/miniupnpc/minisoap.h | 15 - ext/bin/miniupnpc/include/miniupnpc/minissdpc.h | 15 - ext/bin/miniupnpc/include/miniupnpc/miniupnpc.h | 154 ----- .../include/miniupnpc/miniupnpc_declspec.h | 21 - .../miniupnpc/include/miniupnpc/miniupnpcstrings.h | 23 - .../miniupnpc/include/miniupnpc/miniupnpctypes.h | 19 - ext/bin/miniupnpc/include/miniupnpc/miniwget.h | 30 - ext/bin/miniupnpc/include/miniupnpc/minixml.h | 37 -- .../miniupnpc/include/miniupnpc/portlistingparse.h | 65 --- ext/bin/miniupnpc/include/miniupnpc/receivedata.h | 19 - ext/bin/miniupnpc/include/miniupnpc/upnpcommands.h | 348 ----------- ext/bin/miniupnpc/include/miniupnpc/upnperrors.h | 26 - .../miniupnpc/include/miniupnpc/upnpreplyparse.h | 63 -- ext/bin/miniupnpc/windows-x64/miniupnpc.lib | Bin 731616 -> 0 bytes ext/bin/miniupnpc/windows-x86/miniupnpc.lib | Bin 702786 -> 0 bytes ext/installfiles/windows/ZeroTier One.aip | 2 +- ext/miniupnpc/connecthostport.c | 2 + ext/miniupnpc/minisoap.c | 7 + ext/miniupnpc/minissdpc.c | 2 + ext/miniupnpc/miniupnpc.c | 1 + ext/miniupnpc/miniwget.c | 7 + ext/miniupnpc/minixml.c | 1 + ext/miniupnpc/minixmlvalid.c | 1 + ext/miniupnpc/upnpcommands.c | 1 + ext/miniupnpc/upnpreplyparse.c | 1 + osdep/UPNPClient.cpp | 6 +- windows/ZeroTierOne/ZeroTierOne.vcxproj | 45 +- windows/ZeroTierOne/ZeroTierOne.vcxproj.filters | 93 +++ 35 files changed, 157 insertions(+), 1633 deletions(-) delete mode 100644 ext/bin/miniupnpc/Changelog.txt delete mode 100644 ext/bin/miniupnpc/LICENSE delete mode 100644 ext/bin/miniupnpc/README.md delete mode 100644 ext/bin/miniupnpc/VERSION delete mode 100644 ext/bin/miniupnpc/include/miniupnpc/codelength.h delete mode 100644 ext/bin/miniupnpc/include/miniupnpc/connecthostport.h delete mode 100644 ext/bin/miniupnpc/include/miniupnpc/igd_desc_parse.h delete mode 100644 ext/bin/miniupnpc/include/miniupnpc/minisoap.h delete mode 100644 ext/bin/miniupnpc/include/miniupnpc/minissdpc.h delete mode 100644 ext/bin/miniupnpc/include/miniupnpc/miniupnpc.h delete mode 100644 ext/bin/miniupnpc/include/miniupnpc/miniupnpc_declspec.h delete mode 100644 ext/bin/miniupnpc/include/miniupnpc/miniupnpcstrings.h delete mode 100644 ext/bin/miniupnpc/include/miniupnpc/miniupnpctypes.h delete mode 100644 ext/bin/miniupnpc/include/miniupnpc/miniwget.h delete mode 100644 ext/bin/miniupnpc/include/miniupnpc/minixml.h delete mode 100644 ext/bin/miniupnpc/include/miniupnpc/portlistingparse.h delete mode 100644 ext/bin/miniupnpc/include/miniupnpc/receivedata.h delete mode 100644 ext/bin/miniupnpc/include/miniupnpc/upnpcommands.h delete mode 100644 ext/bin/miniupnpc/include/miniupnpc/upnperrors.h delete mode 100644 ext/bin/miniupnpc/include/miniupnpc/upnpreplyparse.h delete mode 100644 ext/bin/miniupnpc/windows-x64/miniupnpc.lib delete mode 100644 ext/bin/miniupnpc/windows-x86/miniupnpc.lib diff --git a/ext/bin/miniupnpc/Changelog.txt b/ext/bin/miniupnpc/Changelog.txt deleted file mode 100644 index bb2abb7e..00000000 --- a/ext/bin/miniupnpc/Changelog.txt +++ /dev/null @@ -1,633 +0,0 @@ -$Id: Changelog.txt,v 1.208 2015/07/15 12:18:59 nanard Exp $ -miniUPnP client Changelog. - -2015/07/15: - Check malloc/calloc - -2015/06/16: - update getDevicesFromMiniSSDPD() to process longer minissdpd - responses - -2015/05/22: - add searchalltypes param to upnpDiscoverDevices() - increments API_VERSION to 13 - -2015/04/30: - upnpc: output version on the terminal - -2015/04/27: - _BSD_SOURCE is deprecated in favor of _DEFAULT_SOURCE - fix CMakeLists.txt COMPILE_DEFINITIONS - fix getDevicesFromMiniSSDPD() not setting scope_id - improve -r command of upnpc command line tool - -2014/11/17: - search all : - upnpDiscoverDevices() / upnpDiscoverAll() functions - listdevices executable - increment API_VERSION to 12 - validate igd_desc_parse - -2014/11/13: - increment API_VERSION to 11 - -2014/11/05: - simplified function GetUPNPUrls() - -2014/09/11: - use remoteHost arg of DeletePortMapping - -2014/09/06: - Fix python3 build - -2014/07/01: - Fix parsing of IGD2 root descriptions - -2014/06/10: - rename LIBSPEC to MINIUPNP_LIBSPEC - -2014/05/15: - Add support for IGD2 AddAnyPortMapping and DeletePortMappingRange - -2014/02/05: - handle EINPROGRESS after connect() - -2014/02/03: - minixml now handle XML comments - -VERSION 1.9 : released 2014/01/31 - -2014/01/31: - added argument remoteHost to UPNP_GetSpecificPortMappingEntry() - increment API_VERSION to 10 - -2013/12/09: - --help and -h arguments in upnpc.c - -2013/10/07: - fixed potential buffer overrun in miniwget.c - Modified UPNP_GetValidIGD() to check for ExternalIpAddress - -2013/08/01: - define MAXHOSTNAMELEN if not already done - -2013/06/06: - update upnpreplyparse to allow larger values (128 chars instead of 64) - -2013/05/14: - Update upnpreplyparse to take into account "empty" elements - validate upnpreplyparse.c code with "make check" - -2013/05/03: - Fix Solaris build thanks to Maciej Małecki - -2013/04/27: - Fix testminiwget.sh for BSD - -2013/03/23: - Fixed Makefile for *BSD - -2013/03/11: - Update Makefile to use JNAerator version 0.11 - -2013/02/11: - Fix testminiwget.sh for use with dash - Use $(DESTDIR) in Makefile - -VERSION 1.8 : released 2013/02/06 - -2012/10/16: - fix testminiwget with no IPv6 support - -2012/09/27: - Rename all include guards to not clash with C99 - (7.1.3 Reserved identifiers). - -2012/08/30: - Added -e option to upnpc program (set description for port mappings) - -2012/08/29: - Python 3 support (thanks to Christopher Foo) - -2012/08/11: - Fix a memory link in UPNP_GetValidIGD() - Try to handle scope id in link local IPv6 URL under MS Windows - -2012/07/20: - Disable HAS_IP_MREQN on DragonFly BSD - -2012/06/28: - GetUPNPUrls() now inserts scope into link-local IPv6 addresses - -2012/06/23: - More error return checks in upnpc.c - #define MINIUPNPC_GET_SRC_ADDR enables receivedata() to get scope_id - parseURL() now parses IPv6 addresses scope - new parameter for miniwget() : IPv6 address scope - increment API_VERSION to 9 - -2012/06/20: - fixed CMakeLists.txt - -2012/05/29 - Improvements in testminiwget.sh - -VERSION 1.7 : released 2012/05/24 - -2012/05/01: - Cleanup settings of CFLAGS in Makefile - Fix signed/unsigned integer comparaisons - -2012/04/20: - Allow to specify protocol with TCP or UDP for -A option - -2012/04/09: - Only try to fetch XML description once in UPNP_GetValidIGD() - Added -ansi flag to compilation, and fixed C++ comments to ANSI C comments. - -2012/04/05: - minor improvements to minihttptestserver.c - -2012/03/15: - upnperrors.c returns valid error string for unrecognized error codes - -2012/03/08: - make minihttptestserver listen on loopback interface instead of 0.0.0.0 - -2012/01/25: - Maven installation thanks to Alexey Kuznetsov - -2012/01/21: - Replace WIN32 macro by _WIN32 - -2012/01/19: - Fixes in java wrappers thanks to Alexey Kuznetsov : - https://github.com/axet/miniupnp/tree/fix-javatest/miniupnpc - Make and install .deb packages (python) thanks to Alexey Kuznetsov : - https://github.com/axet/miniupnp/tree/feature-debbuild/miniupnpc - -2012/01/07: - The multicast interface can now be specified by name with IPv4. - -2012/01/02: - Install man page - -2011/11/25: - added header to Port Mappings list in upnpc.c - -2011/10/09: - Makefile : make clean now removes jnaerator generated files. - MINIUPNPC_VERSION in miniupnpc.h (updated by make) - -2011/09/12: - added rootdescURL to UPNPUrls structure. - -VERSION 1.6 : released 2011/07/25 - -2011/07/25: - Update doc for version 1.6 release - -2011/06/18: - Fix for windows in miniwget.c - -2011/06/04: - display remote host in port mapping listing - -2011/06/03: - Fix in make install : there were missing headers - -2011/05/26: - Fix the socket leak in miniwget thanks to Richard Marsh. - Permit to add leaseduration in -a command. Display lease duration. - -2011/05/15: - Try both LinkLocal and SiteLocal multicast address for SSDP in IPv6 - -2011/05/09: - add a test in testminiwget.sh. - more error checking in miniwget.c - -2011/05/06: - Adding some tool to test and validate miniwget.c - simplified and debugged miniwget.c - -2011/04/11: - moving ReceiveData() to a receivedata.c file. - parsing presentation url - adding IGD v2 WANIPv6FirewallControl commands - -2011/04/10: - update of miniupnpcmodule.c - comments in miniwget.c, update in testminiwget - Adding errors codes from IGD v2 - new functions in upnpc.c for IGD v2 - -2011/04/09: - Support for litteral ip v6 address in miniwget - -2011/04/08: - Adding support for urn:schemas-upnp-org:service:WANIPv6FirewallControl:1 - Updating APIVERSION - Supporting IPV6 in upnpDiscover() - Adding a -6 option to upnpc command line tool - -2011/03/18: - miniwget/parseURL() : return an error when url param is null. - fixing GetListOfPortMappings() - -2011/03/14: - upnpDiscover() now reporting an error code. - improvements in comments. - -2011/03/11: - adding miniupnpcstrings.h.cmake and CMakeLists.txt files. - -2011/02/15: - Implementation of GetListOfPortMappings() - -2011/02/07: - updates to minixml to support character data starting with spaces - minixml now support CDATA - upnpreplyparse treats specificaly - change in simpleUPnPcommand to return the buffer (simplification) - -2011/02/06: - Added leaseDuration argument to AddPortMapping() - Starting to implement GetListOfPortMappings() - -2011/01/11: - updating wingenminiupnpcstrings.c - -2011/01/04: - improving updateminiupnpcstrings.sh - -VERSION 1.5 : released 2011/01/01 - -2010/12/21: - use NO_GETADDRINFO macro to disable the use of getaddrinfo/freeaddrinfo - -2010/12/11: - Improvements on getHTTPResponse() code. - -2010/12/09: - new code for miniwget that handle Chunked transfer encoding - using getHTTPResponse() in SOAP call code - Adding MANIFEST.in for 'python setup.py bdist_rpm' - -2010/11/25: - changes to minissdpc.c to compile under Win32. - see http://miniupnp.tuxfamily.org/forum/viewtopic.php?t=729 - -2010/09/17: - Various improvement to Makefile from Michał Górny - -2010/08/05: - Adding the script "external-ip.sh" from Reuben Hawkins - -2010/06/09: - update to python module to match modification made on 2010/04/05 - update to Java test code to match modification made on 2010/04/05 - all UPNP_* function now return an error if the SOAP request failed - at HTTP level. - -2010/04/17: - Using GetBestRoute() under win32 in order to find the - right interface to use. - -2010/04/12: - Retrying with HTTP/1.1 if HTTP/1.0 failed. see - http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=1703 - -2010/04/07: - avoid returning duplicates in upnpDiscover() - -2010/04/05: - Create a connecthostport.h/.c with connecthostport() function - and use it in miniwget and miniupnpc. - Use getnameinfo() instead of inet_ntop or inet_ntoa - Work to make miniupnpc IPV6 compatible... - Add java test code. - Big changes in order to support device having both WANIPConnection - and WANPPPConnection. - -2010/04/04: - Use getaddrinfo() instead of gethostbyname() in miniwget. - -2010/01/06: - #define _DARWIN_C_SOURCE for Mac OS X - -2009/12/19: - Improve MinGW32 build - -2009/12/11: - adding a MSVC9 project to build the static library and executable - -2009/12/10: - Fixing some compilation stuff for Windows/MinGW - -2009/12/07: - adaptations in Makefile and updateminiupnpcstring.sh for AmigaOS - some fixes for Windows when using virtual ethernet adapters (it is the - case with VMWare installed). - -2009/12/04: - some fixes for AmigaOS compilation - Changed HTTP version to HTTP/1.0 for Soap too (to prevent chunked - transfer encoding) - -2009/12/03: - updating printIDG and testigddescparse.c for debug. - modifications to compile under AmigaOS - adding a testminiwget program - Changed miniwget to advertise itself as HTTP/1.0 to prevent chunked - transfer encoding - -2009/11/26: - fixing updateminiupnpcstrings.sh to take into account - which command that does not return an error code. - -VERSION 1.4 : released 2009/10/30 - -2009/10/16: - using Py_BEGIN_ALLOW_THREADS and Py_END_ALLOW_THREADS in python module. - -2009/10/10: - Some fixes for compilation under Solaris - compilation fixes : http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=1464 - -2009/09/21: - fixing the code to ignore EINTR during connect() calls. - -2009/08/07: - Set socket timeout for connect() - Some cleanup in miniwget.c - -2009/08/04: - remove multiple redirections with -d in upnpc.c - Print textual error code in upnpc.c - Ignore EINTR during the connect() and poll() calls. - -2009/07/29: - fix in updateminiupnpcstrings.sh if OS name contains "/" - Sending a correct value for MX: field in SSDP request - -2009/07/20: - Change the Makefile to compile under Mac OS X - Fixed a stackoverflow in getDevicesFromMiniSSDPD() - -2009/07/09: - Compile under Haiku - generate miniupnpcstrings.h.in from miniupnpcstrings.h - -2009/06/04: - patching to compile under CygWin and cross compile for minGW - -VERSION 1.3 : - -2009/04/17: - updating python module - Use strtoull() when using C99 - -2009/02/28: - Fixed miniwget.c for compiling under sun - -2008/12/18: - cleanup in Makefile (thanks to Paul de Weerd) - minissdpc.c : win32 compatibility - miniupnpc.c : changed xmlns prefix from 'm' to 'u' - Removed NDEBUG (using DEBUG) - -2008/10/14: - Added the ExternalHost argument to DeletePortMapping() - -2008/10/11: - Added the ExternalHost argument to AddPortMapping() - Put a correct User-Agent: header in HTTP requests. - -VERSION 1.2 : - -2008/10/07: - Update docs - -2008/09/25: - Integrated sameport patch from Dario Meloni : Added a "sameport" - argument to upnpDiscover(). - -2008/07/18: - small modif to make Clang happy :) - -2008/07/17: - #define SOAPPREFIX "s" in miniupnpc.c in order to remove SOAP-ENV... - -2008/07/14: - include declspec.h in installation (to /usr/include/miniupnpc) - -VERSION 1.1 : - -2008/07/04: - standard options for install/ln instead of gnu-specific stuff. - -2008/07/03: - now builds a .dll and .lib with win32. (mingw32) - -2008/04/28: - make install now install the binary of the upnpc tool - -2008/04/27: - added testupnpigd.py - added error strings for miniupnpc "internal" errors - improved python module error/exception reporting. - -2008/04/23: - Completely rewrite igd_desc_parse.c in order to be compatible with - Linksys WAG200G - Added testigddescparse - updated python module - -VERSION 1.0 : - -2008/02/21: - put some #ifdef DEBUG around DisplayNameValueList() - -2008/02/18: - Improved error reporting in upnpcommands.c - UPNP_GetStatusInfo() returns LastConnectionError - -2008/02/16: - better error handling in minisoap.c - improving display of "valid IGD found" in upnpc.c - -2008/02/03: - Fixing UPNP_GetValidIGD() - improved make install :) - -2007/12/22: - Adding upnperrors.c/h to provide a strupnperror() function - used to translate UPnP error codes to string. - -2007/12/19: - Fixing getDevicesFromMiniSSDPD() - improved error reporting of UPnP functions - -2007/12/18: - It is now possible to specify a different location for MiniSSDPd socket. - working with MiniSSDPd is now more efficient. - python module improved. - -2007/12/16: - improving error reporting - -2007/12/13: - Try to improve compatibility by using HTTP/1.0 instead of 1.1 and - XML a bit different for SOAP. - -2007/11/25: - fixed select() call for linux - -2007/11/15: - Added -fPIC to CFLAG for better shared library code. - -2007/11/02: - Fixed a potential socket leak in miniwget2() - -2007/10/16: - added a parameter to upnpDiscover() in order to allow the use of another - interface than the default multicast interface. - -2007/10/12: - Fixed the creation of symbolic link in Makefile - -2007/10/08: - Added man page - -2007/10/02: - fixed memory bug in GetUPNPUrls() - -2007/10/01: - fixes in the Makefile - Added UPNP_GetIGDFromUrl() and adapted the sample program accordingly. - Added SONAME in the shared library to please debian :) - fixed MS Windows compilation (minissdpd is not available under MS Windows). - -2007/09/25: - small change to Makefile to be able to install in a different location - (default is /usr) - -2007/09/24: - now compiling both shared and static library - -2007/09/19: - Cosmetic changes on upnpc.c - -2007/09/02: - adapting to new miniSSDPd (release version ?) - -2007/08/31: - Usage of miniSSDPd to skip discovery process. - -2007/08/27: - fixed python module to allow compilation with Python older than Python 2.4 - -2007/06/12: - Added a python module. - -2007/05/19: - Fixed compilation under MinGW - -2007/05/15: - fixed a memory leak in AddPortMapping() - Added testupnpreplyparse executable to check the parsing of - upnp soap messages - minixml now ignore namespace prefixes. - -2007/04/26: - upnpc now displays external ip address with -s or -l - -2007/04/11: - changed MINIUPNPC_URL_MAXSIZE to 128 to accomodate the "BT Voyager 210" - -2007/03/19: - cleanup in miniwget.c - -2007/03/01: - Small typo fix... - -2007/01/30: - Now parsing the HTTP header from SOAP responses in order to - get content-length value. - -2007/01/29: - Fixed the Soap Query to speedup the HTTP request. - added some Win32 DLL stuff... - -2007/01/27: - Fixed some WIN32 compatibility issues - -2006/12/14: - Added UPNPIGD_IsConnected() function in miniupnp.c/.h - Added UPNP_GetValidIGD() in miniupnp.c/.h - cleaned upnpc.c main(). now using UPNP_GetValidIGD() - -2006/12/07: - Version 1.0-RC1 released - -2006/12/03: - Minor changes to compile under SunOS/Solaris - -2006/11/30: - made a minixml parser validator program - updated minixml to handle attributes correctly - -2006/11/22: - Added a -r option to the upnpc sample thanks to Alexander Hubmann. - -2006/11/19: - Cleanup code to make it more ANSI C compliant - -2006/11/10: - detect and display local lan address. - -2006/11/04: - Packets and Bytes Sent/Received are now unsigned int. - -2006/11/01: - Bug fix thanks to Giuseppe D'Angelo - -2006/10/31: - C++ compatibility for .h files. - Added a way to get ip Address on the LAN used to reach the IGD. - -2006/10/25: - Added M-SEARCH to the services in the discovery process. - -2006/10/22: - updated the Makefile to use makedepend, added a "make install" - update Makefile - -2006/10/20: - fixing the description url parsing thanks to patch sent by - Wayne Dawe. - Fixed/translated some comments. - Implemented a better discover process, first looking - for IGD then for root devices (as some devices only reply to - M-SEARCH for root devices). - -2006/09/02: - added freeUPNPDevlist() function. - -2006/08/04: - More command line arguments checking - -2006/08/01: - Added the .bat file to compile under Win32 with minGW32 - -2006/07/31: - Fixed the rootdesc parser (igd_desc_parse.c) - -2006/07/20: - parseMSEARCHReply() is now returning the ST: line as well - starting changes to detect several UPnP devices on the network - -2006/07/19: - using GetCommonLinkProperties to get down/upload bitrate - diff --git a/ext/bin/miniupnpc/LICENSE b/ext/bin/miniupnpc/LICENSE deleted file mode 100644 index cb5a0604..00000000 --- a/ext/bin/miniupnpc/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -MiniUPnPc -Copyright (c) 2005-2015, 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. - 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/VERSION b/ext/bin/miniupnpc/VERSION deleted file mode 100644 index 2e0e38c6..00000000 --- a/ext/bin/miniupnpc/VERSION +++ /dev/null @@ -1 +0,0 @@ -1.9 diff --git a/ext/bin/miniupnpc/include/miniupnpc/codelength.h b/ext/bin/miniupnpc/include/miniupnpc/codelength.h deleted file mode 100644 index f5f8e30f..00000000 --- a/ext/bin/miniupnpc/include/miniupnpc/codelength.h +++ /dev/null @@ -1,54 +0,0 @@ -/* $Id: codelength.h,v 1.5 2015/07/09 12:40:18 nanard Exp $ */ -/* Project : miniupnp - * Author : Thomas BERNARD - * copyright (c) 2005-2015 Thomas Bernard - * This software is subjet to the conditions detailed in the - * provided LICENCE file. */ -#ifndef CODELENGTH_H_INCLUDED -#define CODELENGTH_H_INCLUDED - -/* Encode length by using 7bit per Byte : - * Most significant bit of each byte specifies that the - * following byte is part of the code */ - -/* n : unsigned - * p : unsigned char * - */ -#define DECODELENGTH(n, p) n = 0; \ - do { n = (n << 7) | (*p & 0x7f); } \ - while((*(p++)&0x80) && (n<(1<<25))); - -/* n : unsigned - * READ : function/macro to read one byte (unsigned char) - */ -#define DECODELENGTH_READ(n, READ) \ - n = 0; \ - do { \ - unsigned char c; \ - READ(c); \ - n = (n << 7) | (c & 0x07f); \ - if(!(c&0x80)) break; \ - } while(n<(1<<25)); - -/* n : unsigned - * p : unsigned char * - * p_limit : unsigned char * - */ -#define DECODELENGTH_CHECKLIMIT(n, p, p_limit) \ - n = 0; \ - do { \ - if((p) >= (p_limit)) break; \ - n = (n << 7) | (*(p) & 0x7f); \ - } while((*((p)++)&0x80) && (n<(1<<25))); - - -/* n : unsigned - * p : unsigned char * - */ -#define CODELENGTH(n, p) if(n>=268435456) *(p++) = (n >> 28) | 0x80; \ - if(n>=2097152) *(p++) = (n >> 21) | 0x80; \ - if(n>=16384) *(p++) = (n >> 14) | 0x80; \ - if(n>=128) *(p++) = (n >> 7) | 0x80; \ - *(p++) = n & 0x7f; - -#endif /* CODELENGTH_H_INCLUDED */ diff --git a/ext/bin/miniupnpc/include/miniupnpc/connecthostport.h b/ext/bin/miniupnpc/include/miniupnpc/connecthostport.h deleted file mode 100644 index 56941d6f..00000000 --- a/ext/bin/miniupnpc/include/miniupnpc/connecthostport.h +++ /dev/null @@ -1,18 +0,0 @@ -/* $Id: connecthostport.h,v 1.3 2012/09/27 15:42:10 nanard Exp $ */ -/* Project: miniupnp - * http://miniupnp.free.fr/ - * Author: Thomas Bernard - * Copyright (c) 2010-2012 Thomas Bernard - * This software is subjects to the conditions detailed - * in the LICENCE file provided within this distribution */ -#ifndef CONNECTHOSTPORT_H_INCLUDED -#define CONNECTHOSTPORT_H_INCLUDED - -/* 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); - -#endif - diff --git a/ext/bin/miniupnpc/include/miniupnpc/igd_desc_parse.h b/ext/bin/miniupnpc/include/miniupnpc/igd_desc_parse.h deleted file mode 100644 index 0de546b6..00000000 --- a/ext/bin/miniupnpc/include/miniupnpc/igd_desc_parse.h +++ /dev/null @@ -1,49 +0,0 @@ -/* $Id: igd_desc_parse.h,v 1.12 2014/11/17 17:19:13 nanard Exp $ */ -/* Project : miniupnp - * http://miniupnp.free.fr/ - * Author : Thomas Bernard - * Copyright (c) 2005-2014 Thomas Bernard - * This software is subject to the conditions detailed in the - * LICENCE file provided in this distribution. - * */ -#ifndef IGD_DESC_PARSE_H_INCLUDED -#define IGD_DESC_PARSE_H_INCLUDED - -/* Structure to store the result of the parsing of UPnP - * descriptions of Internet Gateway Devices */ -#define MINIUPNPC_URL_MAXSIZE (128) -struct IGDdatas_service { - char controlurl[MINIUPNPC_URL_MAXSIZE]; - char eventsuburl[MINIUPNPC_URL_MAXSIZE]; - char scpdurl[MINIUPNPC_URL_MAXSIZE]; - char servicetype[MINIUPNPC_URL_MAXSIZE]; - /*char devicetype[MINIUPNPC_URL_MAXSIZE];*/ -}; - -struct IGDdatas { - char cureltname[MINIUPNPC_URL_MAXSIZE]; - char urlbase[MINIUPNPC_URL_MAXSIZE]; - char presentationurl[MINIUPNPC_URL_MAXSIZE]; - int level; - /*int state;*/ - /* "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" */ - struct IGDdatas_service CIF; - /* "urn:schemas-upnp-org:service:WANIPConnection:1" - * "urn:schemas-upnp-org:service:WANPPPConnection:1" */ - struct IGDdatas_service first; - /* if both WANIPConnection and WANPPPConnection are present */ - struct IGDdatas_service second; - /* "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1" */ - struct IGDdatas_service IPv6FC; - /* tmp */ - struct IGDdatas_service tmp; -}; - -void IGDstartelt(void *, const char *, int); -void IGDendelt(void *, const char *, int); -void IGDdata(void *, const char *, int); -#ifdef DEBUG -void printIGD(struct IGDdatas *); -#endif /* DEBUG */ - -#endif /* IGD_DESC_PARSE_H_INCLUDED */ diff --git a/ext/bin/miniupnpc/include/miniupnpc/minisoap.h b/ext/bin/miniupnpc/include/miniupnpc/minisoap.h deleted file mode 100644 index 14c859d1..00000000 --- a/ext/bin/miniupnpc/include/miniupnpc/minisoap.h +++ /dev/null @@ -1,15 +0,0 @@ -/* $Id: minisoap.h,v 1.5 2012/09/27 15:42:10 nanard Exp $ */ -/* Project : miniupnp - * Author : Thomas Bernard - * Copyright (c) 2005 Thomas Bernard - * This software is subject to the conditions detailed in the - * LICENCE file provided in this distribution. */ -#ifndef MINISOAP_H_INCLUDED -#define MINISOAP_H_INCLUDED - -/*int httpWrite(int, const char *, int, const char *);*/ -int soapPostSubmit(int, const char *, const char *, unsigned short, - const char *, const char *, const char *); - -#endif - 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/include/miniupnpc/miniupnpc.h b/ext/bin/miniupnpc/include/miniupnpc/miniupnpc.h deleted file mode 100644 index 0eeabc23..00000000 --- a/ext/bin/miniupnpc/include/miniupnpc/miniupnpc.h +++ /dev/null @@ -1,154 +0,0 @@ -/* $Id: miniupnpc.h,v 1.42 2015/07/21 13:16:55 nanard Exp $ */ -/* Project: miniupnp - * http://miniupnp.free.fr/ - * 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 MINIUPNPC_H_INCLUDED -#define MINIUPNPC_H_INCLUDED - -#include "miniupnpc_declspec.h" -#include "igd_desc_parse.h" - -/* error codes : */ -#define UPNPDISCOVER_SUCCESS (0) -#define UPNPDISCOVER_UNKNOWN_ERROR (-1) -#define UPNPDISCOVER_SOCKET_ERROR (-101) -#define UPNPDISCOVER_MEMORY_ERROR (-102) - -/* versions : */ -#define MINIUPNPC_VERSION "1.9.20150721" -#define MINIUPNPC_API_VERSION 13 - -#ifdef __cplusplus -extern "C" { -#endif - -/* Structures definitions : */ -struct UPNParg { const char * elt; const char * val; }; - -char * -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. - * It is up to the caller to free the list with freeUPNPDevlist(). - * 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 sameport is not null, SSDP packets will be sent from the source port - * 1900 (same as destination port) otherwise system assign a source port. - * "searchalltypes" parameter is useful when searching several types, - * if 0, the discovery will stop with the first type returning results. */ -MINIUPNP_LIBSPEC struct UPNPDev * -upnpDiscover(int delay, const char * multicastif, - const char * minissdpdsock, int sameport, - int ipv6, - int * error); - -MINIUPNP_LIBSPEC struct UPNPDev * -upnpDiscoverAll(int delay, const char * multicastif, - const char * minissdpdsock, int sameport, - int ipv6, - int * error); - -MINIUPNP_LIBSPEC struct UPNPDev * -upnpDiscoverDevice(const char * device, int delay, const char * multicastif, - const char * minissdpdsock, int sameport, - int ipv6, - int * error); - -MINIUPNP_LIBSPEC struct UPNPDev * -upnpDiscoverDevices(const char * const deviceTypes[], - int delay, const char * multicastif, - const char * minissdpdsock, int sameport, - int ipv6, - 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. */ -MINIUPNP_LIBSPEC void parserootdesc(const char *, int, struct IGDdatas *); - -/* structure used to get fast access to urls - * controlURL: controlURL of the WANIPConnection - * ipcondescURL: url of the description of the WANIPConnection - * controlURL_CIF: controlURL of the WANCommonInterfaceConfig - * controlURL_6FC: controlURL of the WANIPv6FirewallControl - */ -struct UPNPUrls { - char * controlURL; - char * ipcondescURL; - char * controlURL_CIF; - char * controlURL_6FC; - char * rootdescURL; -}; - -/* UPNP_GetValidIGD() : - * return values : - * 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 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); - -/* UPNP_GetIGDFromUrl() - * Used when skipping the discovery process. - * When succeding, urls, data, and lanaddr arguments are set. - * return value : - * 0 - Not ok - * 1 - OK */ -MINIUPNP_LIBSPEC int -UPNP_GetIGDFromUrl(const char * rootdescurl, - struct UPNPUrls * urls, - struct IGDdatas * data, - char * lanaddr, int lanaddrlen); - -MINIUPNP_LIBSPEC void -GetUPNPUrls(struct UPNPUrls *, struct IGDdatas *, - const char *, unsigned int); - -MINIUPNP_LIBSPEC void -FreeUPNPUrls(struct UPNPUrls *); - -/* return 0 or 1 */ -MINIUPNP_LIBSPEC int UPNPIGD_IsConnected(struct UPNPUrls *, struct IGDdatas *); - - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/ext/bin/miniupnpc/include/miniupnpc/miniupnpc_declspec.h b/ext/bin/miniupnpc/include/miniupnpc/miniupnpc_declspec.h deleted file mode 100644 index 40adb922..00000000 --- a/ext/bin/miniupnpc/include/miniupnpc/miniupnpc_declspec.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef MINIUPNPC_DECLSPEC_H_INCLUDED -#define MINIUPNPC_DECLSPEC_H_INCLUDED - -#if defined(_WIN32) && !defined(MINIUPNP_STATICLIB) - /* for windows dll */ - #ifdef MINIUPNP_EXPORTS - #define MINIUPNP_LIBSPEC __declspec(dllexport) - #else - #define MINIUPNP_LIBSPEC __declspec(dllimport) - #endif -#else - #if defined(__GNUC__) && __GNUC__ >= 4 - /* fix dynlib for OS X 10.9.2 and Apple LLVM version 5.0 */ - #define MINIUPNP_LIBSPEC __attribute__ ((visibility ("default"))) - #else - #define MINIUPNP_LIBSPEC - #endif -#endif - -#endif /* MINIUPNPC_DECLSPEC_H_INCLUDED */ - diff --git a/ext/bin/miniupnpc/include/miniupnpc/miniupnpcstrings.h b/ext/bin/miniupnpc/include/miniupnpc/miniupnpcstrings.h deleted file mode 100644 index 80a1d757..00000000 --- a/ext/bin/miniupnpc/include/miniupnpc/miniupnpcstrings.h +++ /dev/null @@ -1,23 +0,0 @@ -/* $Id: miniupnpcstrings.h.in,v 1.6 2014/11/04 22:31:55 nanard Exp $ */ -/* Project: miniupnp - * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * Author: Thomas Bernard - * Copyright (c) 2005-2014 Thomas Bernard - * This software is subjects to the conditions detailed - * in the LICENCE file provided within this distribution */ -#ifndef MINIUPNPCSTRINGS_H_INCLUDED -#define MINIUPNPCSTRINGS_H_INCLUDED - -#define OS_STRING "Darwin/14.4.0" -#define MINIUPNPC_VERSION_STRING "1.9" - -#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/miniupnpctypes.h b/ext/bin/miniupnpc/include/miniupnpc/miniupnpctypes.h deleted file mode 100644 index 591c32fb..00000000 --- a/ext/bin/miniupnpc/include/miniupnpc/miniupnpctypes.h +++ /dev/null @@ -1,19 +0,0 @@ -/* $Id: miniupnpctypes.h,v 1.2 2012/09/27 15:42:10 nanard Exp $ */ -/* Miniupnp project : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org - * Author : Thomas Bernard - * Copyright (c) 2011 Thomas Bernard - * This software is subject to the conditions detailed in the - * LICENCE file provided within this distribution */ -#ifndef MINIUPNPCTYPES_H_INCLUDED -#define MINIUPNPCTYPES_H_INCLUDED - -#if (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L) -#define UNSIGNED_INTEGER unsigned long long -#define STRTOUI strtoull -#else -#define UNSIGNED_INTEGER unsigned int -#define STRTOUI strtoul -#endif - -#endif - diff --git a/ext/bin/miniupnpc/include/miniupnpc/miniwget.h b/ext/bin/miniupnpc/include/miniupnpc/miniwget.h deleted file mode 100644 index d6db71a8..00000000 --- a/ext/bin/miniupnpc/include/miniupnpc/miniwget.h +++ /dev/null @@ -1,30 +0,0 @@ -/* $Id: miniwget.h,v 1.10 2015/07/21 13:16:55 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. - * */ -#ifndef MINIWGET_H_INCLUDED -#define MINIWGET_H_INCLUDED - -#include "miniupnpc_declspec.h" - -#ifdef __cplusplus -extern "C" { -#endif - -MINIUPNP_LIBSPEC void * getHTTPResponse(int s, int * size); - -MINIUPNP_LIBSPEC void * miniwget(const char *, int *, unsigned int); - -MINIUPNP_LIBSPEC void * miniwget_getaddr(const char *, int *, char *, int, unsigned int); - -int parseURL(const char *, char *, unsigned short *, char * *, unsigned int *); - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/ext/bin/miniupnpc/include/miniupnpc/minixml.h b/ext/bin/miniupnpc/include/miniupnpc/minixml.h deleted file mode 100644 index 9f43aa48..00000000 --- a/ext/bin/miniupnpc/include/miniupnpc/minixml.h +++ /dev/null @@ -1,37 +0,0 @@ -/* $Id: minixml.h,v 1.7 2012/09/27 15:42:10 nanard Exp $ */ -/* minimal xml parser - * - * Project : miniupnp - * Website : http://miniupnp.free.fr/ - * Author : Thomas Bernard - * Copyright (c) 2005 Thomas Bernard - * This software is subject to the conditions detailed in the - * LICENCE file provided in this distribution. - * */ -#ifndef MINIXML_H_INCLUDED -#define MINIXML_H_INCLUDED -#define IS_WHITE_SPACE(c) ((c==' ') || (c=='\t') || (c=='\r') || (c=='\n')) - -/* if a callback function pointer is set to NULL, - * the function is not called */ -struct xmlparser { - const char *xmlstart; - const char *xmlend; - const char *xml; /* pointer to current character */ - int xmlsize; - void * data; - void (*starteltfunc) (void *, const char *, int); - void (*endeltfunc) (void *, const char *, int); - void (*datafunc) (void *, const char *, int); - void (*attfunc) (void *, const char *, int, const char *, int); -}; - -/* parsexml() - * the xmlparser structure must be initialized before the call - * the following structure members have to be initialized : - * xmlstart, xmlsize, data, *func - * xml is for internal usage, xmlend is computed automatically */ -void parsexml(struct xmlparser *); - -#endif - diff --git a/ext/bin/miniupnpc/include/miniupnpc/portlistingparse.h b/ext/bin/miniupnpc/include/miniupnpc/portlistingparse.h deleted file mode 100644 index 661ad1fa..00000000 --- a/ext/bin/miniupnpc/include/miniupnpc/portlistingparse.h +++ /dev/null @@ -1,65 +0,0 @@ -/* $Id: portlistingparse.h,v 1.11 2015/07/21 13:16:55 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 */ -#ifndef PORTLISTINGPARSE_H_INCLUDED -#define PORTLISTINGPARSE_H_INCLUDED - -#include "miniupnpc_declspec.h" -/* for the definition of UNSIGNED_INTEGER */ -#include "miniupnpctypes.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* sample of PortMappingEntry : - - 202.233.2.1 - 2345 - TCP - 2345 - 192.168.1.137 - 1 - dooom - 345 - - */ -typedef enum { PortMappingEltNone, - PortMappingEntry, NewRemoteHost, - NewExternalPort, NewProtocol, - NewInternalPort, NewInternalClient, - NewEnabled, NewDescription, - NewLeaseTime } portMappingElt; - -struct PortMapping { - struct PortMapping * l_next; /* list next element */ - UNSIGNED_INTEGER leaseTime; - unsigned short externalPort; - unsigned short internalPort; - char remoteHost[64]; - char internalClient[64]; - char description[64]; - char protocol[4]; - unsigned char enabled; -}; - -struct PortMappingParserData { - struct PortMapping * l_head; /* list head */ - portMappingElt curelt; -}; - -MINIUPNP_LIBSPEC void -ParsePortListing(const char * buffer, int bufsize, - struct PortMappingParserData * pdata); - -MINIUPNP_LIBSPEC void -FreePortListing(struct PortMappingParserData * pdata); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/ext/bin/miniupnpc/include/miniupnpc/receivedata.h b/ext/bin/miniupnpc/include/miniupnpc/receivedata.h deleted file mode 100644 index 0520a11d..00000000 --- a/ext/bin/miniupnpc/include/miniupnpc/receivedata.h +++ /dev/null @@ -1,19 +0,0 @@ -/* $Id: receivedata.h,v 1.4 2012/09/27 15:42:10 nanard Exp $ */ -/* Project: miniupnp - * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * Author: Thomas Bernard - * Copyright (c) 2011-2012 Thomas Bernard - * This software is subjects to the conditions detailed - * in the LICENCE file provided within this distribution */ -#ifndef RECEIVEDATA_H_INCLUDED -#define RECEIVEDATA_H_INCLUDED - -/* Reads data from the specified socket. - * Returns the number of bytes read if successful, zero if no bytes were - * read or if we timed out. Returns negative if there was an error. */ -int receivedata(int socket, - char * data, int length, - int timeout, unsigned int * scope_id); - -#endif - diff --git a/ext/bin/miniupnpc/include/miniupnpc/upnpcommands.h b/ext/bin/miniupnpc/include/miniupnpc/upnpcommands.h deleted file mode 100644 index 22eda5e3..00000000 --- a/ext/bin/miniupnpc/include/miniupnpc/upnpcommands.h +++ /dev/null @@ -1,348 +0,0 @@ -/* $Id: upnpcommands.h,v 1.31 2015/07/21 13:16:55 nanard Exp $ */ -/* Miniupnp project : 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 within this distribution */ -#ifndef UPNPCOMMANDS_H_INCLUDED -#define UPNPCOMMANDS_H_INCLUDED - -#include "upnpreplyparse.h" -#include "portlistingparse.h" -#include "miniupnpc_declspec.h" -#include "miniupnpctypes.h" - -/* MiniUPnPc return codes : */ -#define UPNPCOMMAND_SUCCESS (0) -#define UPNPCOMMAND_UNKNOWN_ERROR (-1) -#define UPNPCOMMAND_INVALID_ARGS (-2) -#define UPNPCOMMAND_HTTP_ERROR (-3) -#define UPNPCOMMAND_INVALID_RESPONSE (-4) -#define UPNPCOMMAND_MEM_ALLOC_ERROR (-5) - -#ifdef __cplusplus -extern "C" { -#endif - -MINIUPNP_LIBSPEC UNSIGNED_INTEGER -UPNP_GetTotalBytesSent(const char * controlURL, - const char * servicetype); - -MINIUPNP_LIBSPEC UNSIGNED_INTEGER -UPNP_GetTotalBytesReceived(const char * controlURL, - const char * servicetype); - -MINIUPNP_LIBSPEC UNSIGNED_INTEGER -UPNP_GetTotalPacketsSent(const char * controlURL, - const char * servicetype); - -MINIUPNP_LIBSPEC UNSIGNED_INTEGER -UPNP_GetTotalPacketsReceived(const char * controlURL, - const char * servicetype); - -/* UPNP_GetStatusInfo() - * status and lastconnerror are 64 byte buffers - * Return values : - * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR - * or a UPnP Error code */ -MINIUPNP_LIBSPEC int -UPNP_GetStatusInfo(const char * controlURL, - const char * servicetype, - char * status, - unsigned int * uptime, - char * lastconnerror); - -/* UPNP_GetConnectionTypeInfo() - * argument connectionType is a 64 character buffer - * Return Values : - * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR - * or a UPnP Error code */ -MINIUPNP_LIBSPEC int -UPNP_GetConnectionTypeInfo(const char * controlURL, - const char * servicetype, - char * connectionType); - -/* 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. - * - * possible UPnP Errors : - * 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); - -/* UPNP_GetLinkLayerMaxBitRates() - * call WANCommonInterfaceConfig:1#GetCommonLinkProperties - * - * return values : - * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR - * or a UPnP Error Code. */ -MINIUPNP_LIBSPEC int -UPNP_GetLinkLayerMaxBitRates(const char* controlURL, - const char* servicetype, - unsigned int * bitrateDown, - unsigned int * bitrateUp); - -/* UPNP_AddPortMapping() - * if desc is NULL, it will be defaulted to "libminiupnpc" - * remoteHost is usually NULL because IGD don't support it. - * - * Return values : - * 0 : SUCCESS - * NON ZERO : ERROR. Either an UPnP error code or an unknown error. - * - * List of possible UPnP errors for AddPortMapping : - * errorCode errorDescription (short) - Description (long) - * 402 Invalid Args - See UPnP Device Architecture section on Control. - * 501 Action Failed - See UPnP Device Architecture section on Control. - * 606 Action not authorized - The action requested REQUIRES authorization and - * the sender was not authorized. - * 715 WildCardNotPermittedInSrcIP - The source IP address cannot be - * wild-carded - * 716 WildCardNotPermittedInExtPort - The external port cannot be wild-carded - * 718 ConflictInMappingEntry - The port mapping entry specified conflicts - * with a mapping assigned previously to another client - * 724 SamePortValuesRequired - Internal and External port values - * must be the same - * 725 OnlyPermanentLeasesSupported - The NAT implementation only supports - * permanent lease times on port mappings - * 726 RemoteHostOnlySupportsWildcard - RemoteHost must be a wildcard - * and cannot be a specific IP address or DNS name - * 727 ExternalPortOnlySupportsWildcard - ExternalPort must be a wildcard and - * cannot be a specific port value - * 728 NoPortMapsAvailable - There are not enough free ports available to - * complete port mapping. - * 729 ConflictWithOtherMechanisms - Attempted port mapping is not allowed - * due to conflict with other mechanisms. - * 732 WildCardNotPermittedInIntPort - The internal port cannot be wild-carded - */ -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); - -/* UPNP_AddAnyPortMapping() - * if desc is NULL, it will be defaulted to "libminiupnpc" - * remoteHost is usually NULL because IGD don't support it. - * - * Return values : - * 0 : SUCCESS - * NON ZERO : ERROR. Either an UPnP error code or an unknown error. - * - * List of possible UPnP errors for AddPortMapping : - * errorCode errorDescription (short) - Description (long) - * 402 Invalid Args - See UPnP Device Architecture section on Control. - * 501 Action Failed - See UPnP Device Architecture section on Control. - * 606 Action not authorized - The action requested REQUIRES authorization and - * the sender was not authorized. - * 715 WildCardNotPermittedInSrcIP - The source IP address cannot be - * wild-carded - * 716 WildCardNotPermittedInExtPort - The external port cannot be wild-carded - * 728 NoPortMapsAvailable - There are not enough free ports available to - * complete port mapping. - * 729 ConflictWithOtherMechanisms - Attempted port mapping is not allowed - * due to conflict with other mechanisms. - * 732 WildCardNotPermittedInIntPort - The internal port cannot be wild-carded - */ -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); - -/* UPNP_DeletePortMapping() - * Use same argument values as what was used for AddPortMapping(). - * remoteHost is usually NULL because IGD don't support it. - * Return Values : - * 0 : SUCCESS - * NON ZERO : error. Either an UPnP error code or an undefined error. - * - * List of possible UPnP errors for DeletePortMapping : - * 402 Invalid Args - See UPnP Device Architecture section on Control. - * 606 Action not authorized - The action requested REQUIRES authorization - * and the sender was not authorized. - * 714 NoSuchEntryInArray - The specified value does not exist in the array */ -MINIUPNP_LIBSPEC int -UPNP_DeletePortMapping(const char * controlURL, const char * servicetype, - const char * extPort, const char * proto, - const char * remoteHost); - -/* UPNP_DeletePortRangeMapping() - * Use same argument values as what was used for AddPortMapping(). - * remoteHost is usually NULL because IGD don't support it. - * Return Values : - * 0 : SUCCESS - * NON ZERO : error. Either an UPnP error code or an undefined error. - * - * List of possible UPnP errors for DeletePortMapping : - * 606 Action not authorized - The action requested REQUIRES authorization - * and the sender was not authorized. - * 730 PortMappingNotFound - This error message is returned if no port - * mapping is found in the specified range. - * 733 InconsistentParameters - NewStartPort and NewEndPort values are not consistent. */ -MINIUPNP_LIBSPEC int -UPNP_DeletePortMappingRange(const char * controlURL, const char * servicetype, - const char * extPortStart, const char * extPortEnd, - const char * proto, - const char * manage); - -/* UPNP_GetPortMappingNumberOfEntries() - * not supported by all routers */ -MINIUPNP_LIBSPEC int -UPNP_GetPortMappingNumberOfEntries(const char* controlURL, - const char* servicetype, - unsigned int * num); - -/* UPNP_GetSpecificPortMappingEntry() - * retrieves an existing port mapping - * params : - * in extPort - * in proto - * in remoteHost - * out intClient (16 bytes) - * out intPort (6 bytes) - * out desc (80 bytes) - * out enabled (4 bytes) - * out leaseDuration (16 bytes) - * - * return value : - * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR - * or a UPnP Error Code. - * - * List of possible UPnP errors for _GetSpecificPortMappingEntry : - * 402 Invalid Args - See UPnP Device Architecture section on Control. - * 501 Action Failed - See UPnP Device Architecture section on Control. - * 606 Action not authorized - The action requested REQUIRES authorization - * and the sender was not authorized. - * 714 NoSuchEntryInArray - The specified value does not exist in the array. - */ -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); - -/* UPNP_GetGenericPortMappingEntry() - * params : - * in index - * out extPort (6 bytes) - * out intClient (16 bytes) - * out intPort (6 bytes) - * out protocol (4 bytes) - * out desc (80 bytes) - * out enabled (4 bytes) - * out rHost (64 bytes) - * out duration (16 bytes) - * - * return value : - * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR - * or a UPnP Error Code. - * - * Possible UPNP Error codes : - * 402 Invalid Args - See UPnP Device Architecture section on Control. - * 606 Action not authorized - The action requested REQUIRES authorization - * and the sender was not authorized. - * 713 SpecifiedArrayIndexInvalid - The specified array index is out of bounds - */ -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); - -/* UPNP_GetListOfPortMappings() Available in IGD v2 - * - * - * 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); - -/* IGD:2, functions for service WANIPv6FirewallControl:1 */ -MINIUPNP_LIBSPEC int -UPNP_GetFirewallStatus(const char * controlURL, - const char * servicetype, - int * firewallEnabled, - int * inboundPinholeAllowed); - -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); - -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); - -MINIUPNP_LIBSPEC int -UPNP_UpdatePinhole(const char * controlURL, const char * servicetype, - const char * uniqueID, - const char * leaseTime); - -MINIUPNP_LIBSPEC int -UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char * uniqueID); - -MINIUPNP_LIBSPEC int -UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype, - const char * uniqueID, int * isWorking); - -MINIUPNP_LIBSPEC int -UPNP_GetPinholePackets(const char * controlURL, const char * servicetype, - const char * uniqueID, int * packets); - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/ext/bin/miniupnpc/include/miniupnpc/upnperrors.h b/ext/bin/miniupnpc/include/miniupnpc/upnperrors.h deleted file mode 100644 index 3115aee5..00000000 --- a/ext/bin/miniupnpc/include/miniupnpc/upnperrors.h +++ /dev/null @@ -1,26 +0,0 @@ -/* $Id: upnperrors.h,v 1.6 2015/07/21 13:16:55 nanard Exp $ */ -/* (c) 2007-2015 Thomas Bernard - * All rights reserved. - * MiniUPnP Project. - * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * This software is subjet to the conditions detailed in the - * provided LICENCE file. */ -#ifndef UPNPERRORS_H_INCLUDED -#define UPNPERRORS_H_INCLUDED - -#include "miniupnpc_declspec.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* strupnperror() - * Return a string description of the UPnP error code - * or NULL for undefinded errors */ -MINIUPNP_LIBSPEC const char * strupnperror(int err); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/ext/bin/miniupnpc/include/miniupnpc/upnpreplyparse.h b/ext/bin/miniupnpc/include/miniupnpc/upnpreplyparse.h deleted file mode 100644 index 6badd15b..00000000 --- a/ext/bin/miniupnpc/include/miniupnpc/upnpreplyparse.h +++ /dev/null @@ -1,63 +0,0 @@ -/* $Id: upnpreplyparse.h,v 1.19 2014/10/27 16:33:19 nanard Exp $ */ -/* MiniUPnP project - * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2013 Thomas Bernard - * This software is subject to the conditions detailed - * in the LICENCE file provided within the distribution */ - -#ifndef UPNPREPLYPARSE_H_INCLUDED -#define UPNPREPLYPARSE_H_INCLUDED - -#ifdef __cplusplus -extern "C" { -#endif - -struct NameValue { - struct NameValue * l_next; - char name[64]; - char value[128]; -}; - -struct NameValueParserData { - struct NameValue * l_head; - char curelt[64]; - char * portListing; - int portListingLength; - int topelt; - const char * cdata; - int cdatalen; -}; - -/* ParseNameValue() */ -void -ParseNameValue(const char * buffer, int bufsize, - struct NameValueParserData * data); - -/* ClearNameValueList() */ -void -ClearNameValueList(struct NameValueParserData * pdata); - -/* GetValueFromNameValueList() */ -char * -GetValueFromNameValueList(struct NameValueParserData * pdata, - const char * Name); - -#if 0 -/* GetValueFromNameValueListIgnoreNS() */ -char * -GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata, - const char * Name); -#endif - -/* DisplayNameValueList() */ -#ifdef DEBUG -void -DisplayNameValueList(char * buffer, int bufsize); -#endif - -#ifdef __cplusplus -} -#endif - -#endif - 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 Binary files a/ext/bin/miniupnpc/windows-x64/miniupnpc.lib and /dev/null 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 Binary files a/ext/bin/miniupnpc/windows-x86/miniupnpc.lib and /dev/null differ diff --git a/ext/installfiles/windows/ZeroTier One.aip b/ext/installfiles/windows/ZeroTier One.aip index 3042005e..8c3aa6bf 100644 --- a/ext/installfiles/windows/ZeroTier One.aip +++ b/ext/installfiles/windows/ZeroTier One.aip @@ -24,7 +24,7 @@ - + diff --git a/ext/miniupnpc/connecthostport.c b/ext/miniupnpc/connecthostport.c index 1f2a032e..854203e0 100644 --- a/ext/miniupnpc/connecthostport.c +++ b/ext/miniupnpc/connecthostport.c @@ -5,6 +5,8 @@ * 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 diff --git a/ext/miniupnpc/minisoap.c b/ext/miniupnpc/minisoap.c index 0b56558e..478bce6b 100644 --- a/ext/miniupnpc/minisoap.c +++ b/ext/miniupnpc/minisoap.c @@ -1,3 +1,4 @@ +#define _CRT_SECURE_NO_WARNINGS /* $Id: minisoap.c,v 1.24 2015/10/26 17:05:07 nanard Exp $ */ /* Project : miniupnp * Author : Thomas Bernard @@ -19,7 +20,13 @@ #include #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 diff --git a/ext/miniupnpc/minissdpc.c b/ext/miniupnpc/minissdpc.c index 5a426739..a371d161 100644 --- a/ext/miniupnpc/minissdpc.c +++ b/ext/miniupnpc/minissdpc.c @@ -1,3 +1,5 @@ +#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/ diff --git a/ext/miniupnpc/miniupnpc.c b/ext/miniupnpc/miniupnpc.c index 4837fe7d..56638881 100644 --- a/ext/miniupnpc/miniupnpc.c +++ b/ext/miniupnpc/miniupnpc.c @@ -1,3 +1,4 @@ +#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 diff --git a/ext/miniupnpc/miniwget.c b/ext/miniupnpc/miniwget.c index 40aa7180..d0dd721b 100644 --- a/ext/miniupnpc/miniwget.c +++ b/ext/miniupnpc/miniwget.c @@ -1,3 +1,4 @@ +#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/ @@ -49,7 +50,13 @@ #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" diff --git a/ext/miniupnpc/minixml.c b/ext/miniupnpc/minixml.c index 3e201ec2..5c79b3c9 100644 --- a/ext/miniupnpc/minixml.c +++ b/ext/miniupnpc/minixml.c @@ -1,3 +1,4 @@ +#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 diff --git a/ext/miniupnpc/minixmlvalid.c b/ext/miniupnpc/minixmlvalid.c index dad14881..a86beba8 100644 --- a/ext/miniupnpc/minixmlvalid.c +++ b/ext/miniupnpc/minixmlvalid.c @@ -1,3 +1,4 @@ +#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/ diff --git a/ext/miniupnpc/upnpcommands.c b/ext/miniupnpc/upnpcommands.c index cabdb50d..660b5d9f 100644 --- a/ext/miniupnpc/upnpcommands.c +++ b/ext/miniupnpc/upnpcommands.c @@ -1,3 +1,4 @@ +#define _CRT_SECURE_NO_WARNINGS /* $Id: upnpcommands.c,v 1.46 2015/07/15 12:19:00 nanard Exp $ */ /* Project : miniupnp * Author : Thomas Bernard diff --git a/ext/miniupnpc/upnpreplyparse.c b/ext/miniupnpc/upnpreplyparse.c index 5de5796a..88d77a66 100644 --- a/ext/miniupnpc/upnpreplyparse.c +++ b/ext/miniupnpc/upnpreplyparse.c @@ -1,3 +1,4 @@ +#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/ diff --git a/osdep/UPNPClient.cpp b/osdep/UPNPClient.cpp index 3193f507..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 { diff --git a/windows/ZeroTierOne/ZeroTierOne.vcxproj b/windows/ZeroTierOne/ZeroTierOne.vcxproj index 82b70400..5da01505 100644 --- a/windows/ZeroTierOne/ZeroTierOne.vcxproj +++ b/windows/ZeroTierOne/ZeroTierOne.vcxproj @@ -22,6 +22,19 @@ + + + + + + + + + + + + + @@ -79,6 +92,22 @@ + + + + + + + + + + + + + + + + @@ -214,11 +243,11 @@ true - NOMINMAX;ZT_TRACE;ZT_USE_MINIUPNPC;%(PreprocessorDefinitions) + NOMINMAX;ZT_TRACE;ZT_USE_MINIUPNPC;MINIUPNP_STATICLIB;%(PreprocessorDefinitions) true - $(SolutionDir)..\ext\bin\miniupnpc\windows-x86\miniupnpc.lib;wsock32.lib;ws2_32.lib;Iphlpapi.lib;Rpcrt4.lib;%(AdditionalDependencies) + wsock32.lib;ws2_32.lib;Iphlpapi.lib;Rpcrt4.lib;%(AdditionalDependencies) false @@ -229,12 +258,12 @@ true - NOMINMAX;ZT_TRACE;ZT_USE_MINIUPNPC;%(PreprocessorDefinitions) + NOMINMAX;ZT_TRACE;ZT_USE_MINIUPNPC;MINIUPNP_STATICLIB;%(PreprocessorDefinitions) false true - $(SolutionDir)..\ext\bin\miniupnpc\windows-x64\miniupnpc.lib;wsock32.lib;ws2_32.lib;Iphlpapi.lib;Rpcrt4.lib;%(AdditionalDependencies) + wsock32.lib;ws2_32.lib;Iphlpapi.lib;Rpcrt4.lib;%(AdditionalDependencies) false @@ -247,7 +276,7 @@ true - ZT_OFFICIAL_RELEASE;ZT_AUTO_UPDATE;ZT_SALSA20_SSE;ZT_USE_MINIUPNPC;NOMINMAX;%(PreprocessorDefinitions) + ZT_OFFICIAL_RELEASE;ZT_AUTO_UPDATE;ZT_SALSA20_SSE;ZT_USE_MINIUPNPC;MINIUPNP_STATICLIB;NOMINMAX;%(PreprocessorDefinitions) MultiThreaded NoExtensions true @@ -259,7 +288,7 @@ true true true - $(SolutionDir)..\ext\bin\miniupnpc\windows-x86\miniupnpc.lib;wsock32.lib;ws2_32.lib;Iphlpapi.lib;Rpcrt4.lib;%(AdditionalDependencies) + wsock32.lib;ws2_32.lib;Iphlpapi.lib;Rpcrt4.lib;%(AdditionalDependencies) false @@ -272,7 +301,7 @@ true - ZT_OFFICIAL_RELEASE;ZT_AUTO_UPDATE;ZT_SALSA20_SSE;ZT_USE_MINIUPNPC;NOMINMAX;%(PreprocessorDefinitions) + ZT_OFFICIAL_RELEASE;ZT_AUTO_UPDATE;ZT_SALSA20_SSE;ZT_USE_MINIUPNPC;MINIUPNP_STATICLIB;NOMINMAX;%(PreprocessorDefinitions) MultiThreaded NotSet true @@ -284,7 +313,7 @@ true true true - $(SolutionDir)..\ext\bin\miniupnpc\windows-x64\miniupnpc.lib;wsock32.lib;ws2_32.lib;Iphlpapi.lib;Rpcrt4.lib;%(AdditionalDependencies) + wsock32.lib;ws2_32.lib;Iphlpapi.lib;Rpcrt4.lib;%(AdditionalDependencies) false diff --git a/windows/ZeroTierOne/ZeroTierOne.vcxproj.filters b/windows/ZeroTierOne/ZeroTierOne.vcxproj.filters index 5a2767e4..6475137c 100644 --- a/windows/ZeroTierOne/ZeroTierOne.vcxproj.filters +++ b/windows/ZeroTierOne/ZeroTierOne.vcxproj.filters @@ -79,6 +79,12 @@ {1a47071e-e51b-4535-89ae-858946f03118} + + {5423fb64-896b-432e-a19d-88d4467f89f9} + + + {56cc3ab8-3336-4a22-9471-c267ee46cd54} + @@ -192,6 +198,45 @@ Source Files\node + + Source Files\ext\miniupnpc + + + Source Files\ext\miniupnpc + + + Source Files\ext\miniupnpc + + + Source Files\ext\miniupnpc + + + Source Files\ext\miniupnpc + + + Source Files\ext\miniupnpc + + + Source Files\ext\miniupnpc + + + Source Files\ext\miniupnpc + + + Source Files\ext\miniupnpc + + + Source Files\ext\miniupnpc + + + Source Files\ext\miniupnpc + + + Source Files\ext\miniupnpc + + + Source Files\ext\miniupnpc + @@ -422,6 +467,54 @@ Header Files\node + + Header Files\ext\miniupnpc + + + Header Files\ext\miniupnpc + + + Header Files\ext\miniupnpc + + + Header Files\ext\miniupnpc + + + Header Files\ext\miniupnpc + + + Header Files\ext\miniupnpc + + + Header Files\ext\miniupnpc + + + Header Files\ext\miniupnpc + + + Header Files\ext\miniupnpc + + + Header Files\ext\miniupnpc + + + Header Files\ext\miniupnpc + + + Header Files\ext\miniupnpc + + + Header Files\ext\miniupnpc + + + Header Files\ext\miniupnpc + + + Header Files\ext\miniupnpc + + + Header Files\ext\miniupnpc + -- cgit v1.2.3 From 456bfea58debd20f39f106263f78a5b116f9d1e5 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 16 Nov 2015 19:27:36 -0800 Subject: Real World -- edge now talks to real net. --- node/Topology.cpp | 8 ++------ world/earth-2015-11-16.bin | Bin 0 -> 494 bytes 2 files changed, 2 insertions(+), 6 deletions(-) create mode 100644 world/earth-2015-11-16.bin diff --git a/node/Topology.cpp b/node/Topology.cpp index 3d1db337..a3faaf23 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -35,12 +35,8 @@ namespace ZeroTier { -// Old root servers -//#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,0x4f,0xdf,0xbf,0xfc,0xbb,0x6c,0x7e,0x15,0x67,0x85,0x1b,0xb4,0x65,0x04,0x01,0xaf,0x56,0xbf,0xe7,0x63,0x9d,0x77,0xef,0xa4,0x1e,0x61,0x53,0x88,0xcb,0x8d,0x78,0xe5,0x47,0x38,0x98,0x5a,0x6c,0x8a,0xdd,0xe6,0x9c,0x65,0xdf,0x1a,0x80,0x63,0xce,0x2e,0x4d,0x48,0x24,0x3d,0x68,0x87,0x96,0x13,0x89,0xba,0x25,0x6f,0xc9,0xb0,0x9f,0x20,0xc5,0x4c,0x51,0x7b,0x30,0xb7,0x5f,0xba,0xca,0xa4,0xc5,0x48,0xa3,0x15,0xab,0x2f,0x1d,0x64,0xe8,0x04,0x42,0xb3,0x1c,0x51,0x8b,0x2a,0x04,0x01,0xf8,0xe1,0x81,0xaf,0x60,0x2f,0x70,0x3e,0xcd,0x0b,0x21,0x38,0x19,0x62,0x02,0xbd,0x0e,0x33,0x1d,0x0a,0x7b,0xf1,0xec,0xad,0xef,0x54,0xb3,0x7b,0x17,0x84,0xaa,0xda,0x0a,0x85,0x5d,0x0b,0x1c,0x05,0x83,0xb9,0x0e,0x3e,0xe3,0xb4,0xd1,0x8b,0x5b,0x64,0xf7,0xcf,0xe1,0xff,0x5d,0xc2,0x2a,0xcf,0x60,0x7b,0x09,0xb4,0xa3,0x86,0x3c,0x5a,0x7e,0x31,0xa0,0xc7,0xb4,0x86,0xe3,0x41,0x33,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}; - -#define ZT_DEFAULT_WORLD_LENGTH 582 -static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {0x01,0x00,0x00,0x00,0x00,0x08,0xea,0xc9,0x0a,0x00,0x00,0x01,0x50,0xa6,0x54,0xe4,0x8e,0x72,0xb0,0x3b,0xbe,0x73,0xda,0xbd,0xfb,0x85,0x77,0x9f,0xc9,0x2e,0x17,0xc8,0x11,0x6e,0xda,0x61,0x80,0xd1,0x41,0xcb,0x7c,0x2d,0x2b,0xa4,0x34,0x75,0x19,0x64,0x20,0x80,0x0a,0x22,0x32,0xf2,0x01,0x6c,0xfe,0x79,0xa6,0x7d,0xec,0x10,0x7e,0x03,0xf3,0xa2,0xa0,0x19,0xc8,0x7c,0xfd,0x6c,0x56,0x52,0xa8,0xfb,0xdc,0xfb,0x93,0x81,0x3e,0xe4,0xe9,0x51,0xc1,0xe1,0x39,0x50,0xcd,0x17,0x82,0x9d,0x74,0xf1,0xa9,0x5b,0x03,0x14,0x2c,0xa7,0xc0,0x7f,0x21,0x8b,0xad,0xdd,0xa5,0x04,0x26,0x35,0xa6,0xab,0xc1,0x49,0x64,0x2c,0xda,0x65,0x52,0x77,0xf3,0xf0,0x70,0x00,0xcd,0xc3,0xff,0x3b,0x19,0x77,0x4c,0xab,0xb6,0x35,0xbb,0x77,0xcf,0x54,0xe5,0x6d,0x01,0x9d,0x43,0x92,0x0a,0x6d,0x00,0x23,0x8e,0x0a,0x3d,0xba,0x36,0xc3,0xa1,0xa4,0xad,0x13,0x8f,0x46,0xff,0xcc,0x8f,0x9e,0xc2,0x3c,0x06,0xf8,0x3b,0xf3,0xa2,0x5f,0x71,0xcc,0x07,0x35,0x7f,0x02,0xd6,0xdd,0xca,0x6a,0xb5,0x00,0x4e,0x76,0x12,0x07,0xd8,0xb4,0x20,0x0b,0xe4,0x4f,0x47,0x8e,0x3d,0xa1,0x48,0xc1,0x60,0x99,0x11,0x0e,0xe7,0x1b,0x64,0x58,0x6d,0xda,0x11,0x8e,0x40,0x22,0xab,0x63,0x68,0x2c,0xe1,0x37,0xda,0x8b,0xa8,0x17,0xfc,0x7f,0x73,0xaa,0x31,0x63,0xf2,0xe3,0x33,0x93,0x3e,0x29,0x94,0xc4,0x6b,0x4f,0x41,0x19,0x30,0x7b,0xe8,0x85,0x5a,0x72,0x00,0x0a,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,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,0x68,0xee,0xb6,0x53,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0xac,0x00,0x08,0x09,0x54,0x00,0x00,0xff,0xfe,0x15,0xf3,0xf4,0x27,0x09,0x04,0x80,0xc7,0xb6,0x09,0x27,0x09,0x06,0x24,0x00,0x61,0x80,0x00,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0x1b,0x10,0x01,0x27,0x09,0x16,0xeb,0xbd,0x6c,0x5d,0x00,0x47,0xd3,0x9b,0xca,0x9d,0x0a,0x5c,0xf7,0x01,0x48,0xe3,0x9f,0x6c,0x45,0x19,0x9e,0x17,0xe0,0xe3,0x2e,0x4e,0x46,0xca,0xc0,0x1a,0xe5,0xbc,0xb2,0x12,0x24,0x13,0x7b,0x09,0x7f,0x40,0xbd,0xd9,0x82,0xa9,0x21,0xc3,0xaa,0xbd,0xcb,0x9a,0xda,0x8b,0x4f,0x2b,0xb0,0x59,0x37,0x53,0xbf,0xdb,0x21,0xcf,0x12,0xea,0xc2,0x8c,0x8d,0x90,0x42,0x00,0x0a,0x04,0x2d,0x21,0x04,0x43,0x27,0x09,0x06,0x26,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x67,0xb7,0x04,0x27,0x09,0x04,0x8b,0xa2,0x9d,0xf3,0x27,0x09,0x06,0x2a,0x01,0x7e,0x01,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x67,0x3f,0xfd,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}; +#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}; Topology::Topology(const RuntimeEnvironment *renv) : RR(renv), diff --git a/world/earth-2015-11-16.bin b/world/earth-2015-11-16.bin new file mode 100644 index 00000000..910ff144 Binary files /dev/null and b/world/earth-2015-11-16.bin differ -- cgit v1.2.3 From 48745eca571a87558a4a0a3741ffa106a6ae14bf Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 16 Nov 2015 19:54:58 -0800 Subject: Fix ARM dpkg build. --- ext/installfiles/linux/buildinstaller.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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" ;; -- cgit v1.2.3 From 9169b6c99902f546fe98e32d24768f4798d3c772 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 17 Nov 2015 09:56:19 -0800 Subject: Fix crash on exit in Windows (does not affect other OSes) and revert debugging tweak in Windows version that prevented service from starting after real install. --- node/Topology.cpp | 43 +++++++++++++++++++++++++------------------ one.cpp | 2 +- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/node/Topology.cpp b/node/Topology.cpp index a3faaf23..c7de22a8 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -96,27 +96,34 @@ Topology::Topology(const RuntimeEnvironment *renv) : Topology::~Topology() { - Buffer pbuf; - std::string all; - - Address *a = (Address *)0; - SharedPtr *p = (SharedPtr *)0; - Hashtable< Address,SharedPtr >::Iterator i(_peers); - while (i.next(a,p)) { - if (std::find(_rootAddresses.begin(),_rootAddresses.end(),*a) == _rootAddresses.end()) { - pbuf.clear(); - try { - (*p)->serialize(pbuf); + Buffer *pbuf = 0; + try { + pbuf = new Buffer(); + std::string all; + + Address *a = (Address *)0; + SharedPtr *p = (SharedPtr *)0; + Hashtable< Address,SharedPtr >::Iterator i(_peers); + while (i.next(a,p)) { + if (std::find(_rootAddresses.begin(),_rootAddresses.end(),*a) == _rootAddresses.end()) { + pbuf->clear(); 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 + (*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); + RR->node->dataStorePut("peers.save",all,true); + + delete pbuf; + } catch ( ... ) { + delete pbuf; + } } SharedPtr Topology::addPeer(const SharedPtr &peer) diff --git a/one.cpp b/one.cpp index 11bcc11e..685034df 100644 --- a/one.cpp +++ b/one.cpp @@ -966,7 +966,7 @@ int main(int argc,char **argv) #ifdef ZT_WIN_RUN_IN_CONSOLE bool winRunFromCommandLine = true; #else - bool winRunFromCommandLine = true; + bool winRunFromCommandLine = false; #endif #endif // __WINDOWS__ -- cgit v1.2.3 From 1c0c3e62dceb96b9dc67b7aadae2a495adde3c7d Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 17 Nov 2015 11:13:44 -0800 Subject: Just add a launch prerequisite for .NET 4.5 -- it's usually there, and if not it can be easily installed. This is mostly an issue on old Windows Server systems, and in that case the admin will likely want to decide how to proceed. --- ext/installfiles/windows/ZeroTier One.aip | 10 +++++----- ext/installfiles/windows/dotNetFx45_Full_setup.exe | Bin 1005568 -> 0 bytes 2 files changed, 5 insertions(+), 5 deletions(-) delete mode 100644 ext/installfiles/windows/dotNetFx45_Full_setup.exe diff --git a/ext/installfiles/windows/ZeroTier One.aip b/ext/installfiles/windows/ZeroTier One.aip index 8c3aa6bf..147094f9 100644 --- a/ext/installfiles/windows/ZeroTier One.aip +++ b/ext/installfiles/windows/ZeroTier One.aip @@ -9,6 +9,8 @@ + + @@ -24,7 +26,7 @@ - + @@ -42,7 +44,7 @@ - + @@ -150,7 +152,6 @@ - @@ -231,7 +232,6 @@ - @@ -260,7 +260,6 @@ - @@ -276,6 +275,7 @@ + diff --git a/ext/installfiles/windows/dotNetFx45_Full_setup.exe b/ext/installfiles/windows/dotNetFx45_Full_setup.exe deleted file mode 100644 index 365b870b..00000000 Binary files a/ext/installfiles/windows/dotNetFx45_Full_setup.exe and /dev/null differ -- cgit v1.2.3 From 6f16f4443833917f9c70de924c818431b1ec64da Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 17 Nov 2015 11:19:58 -0800 Subject: VERSION 1.1.0: Win/Mac UI improvements, improved NAT-t, CIRCUIT_TEST, and more! ZeroTier 1.1.0 introduces a number of fixes and improvements in several areas. We incremented the secondary version to indicate the significance of this release. Version numbering has been a bit ad-hoc in the past. In future versions we will adopt the following scheme: odd-numbered revision numbers like 1.1.1 will indicate development versions, while even numbered ones like 1.1.2 will indicate tagged releases. The public git repo branching has also been revised: master will always be the latest tagged release, dev will be usually-working development, and edge will host maybe-broken "bleeding edge" development. Pull requests on GitHub should generally be made against dev, not master or edge. Other branches that may appear from time to time may be feature or experimental branches. Only master is confirmed good, with dev usually being okay but not guaranteed to be such. (To the extent that any software is ever guaranteed to be anything.) Change summary: User-facing changes and improvements: - Windows now has a new .NET-based native UI, which replaces the old WebControl wrapper around the React UI. This just didn't work well on older Windows systems, and we did not want to bundle 40+ megabytes of web browser with our app just for its very simple UI. - The web UI (still used for Mac and usable in Linux as well) is updated with improved look and simplifications. - Both UIs no longer have the "Peers" tab, since several users reported that non- technical users found this confusing and even alarming (does this mean people can access my system?). This information is visibile with "listpeers" from the command line (zerotier-cli). New features: - Virtual networks that use our RFC4193-based IPv6 numbering scheme now emulate IPv6 NDP for queries that target these addresses within the same network. This allows for faster multicast-free connection init and improved security since the address is now hard-wired to the device ID (which is a crypto token). This does not affect IPv6 NDP for other IPv6 addresses or link-local, which will continue to work normally. This also opens the potential for a reduced footprint multicast-free build for embedded applications. - This version includes beta support for a feature called CIRCUIT_TEST. Network controllers for networks you have joined can now send a special message called CIRCUIT_TEST which allows for ZeroTier-layer link testing and remote diagnosis of link issues. Any operator of a network controller can do this; more documentation will be forthcoming. The only information that may be gathered in this way is IP addressing info and very basic system info (OS, 32/64 bit, ZeroTier version). No personal information, hard drive data, location, or other private info is available. This can only be ordered by a controller of a network you have joined and is secured using cryptographic signatures. - This version includes an alpha version of clustering a.k.a. multi-homing! This powerful feature allows for a single ZeroTier device to be run from multiple endpoints, with connecting peers being handed off to endpoints that are closer via GeoIP lookup and/or are more lightly loaded. Currently this is only suitable for use in our soon-to-be-upgraded root server infrastructure (details will be blogged soon), but in the future it will be capable of hosting multi-homed devices on user networks. This will allow things like (for example) a geo- clustered Cassandra server that appears behind a single IP on a virtual LAN. This feature must be enabled with the ZT_ENABLE_CLUSTER=1 build option. Bug fixes and other improvements (including performance!): - A faster version of the Poly1305 cryptographic MAC function was substituted for sometimes greatly improved performance. - C++ STL std::map was replaced throughout the entire core with a hand-rolled Hashtable implementation for improved performance and in some cases a reduced memory footprint. Some maps are still used in peripheral code that is not performance critical or where ordered keys are needed. - The zerotier-cli and zerotier-idtool symbolic links are now created in /usr/local/bin on OSX to comply with El Capitan file security restrictions. - The OSX tap device driver has been updated. This update may fix issues that some users have reported with bridging on OSX. This new tap device driver drops 32-bit support, but if you have a 32-bit system you can manually install the old driver from ext/bin/tap-mac. - Mac users could experience a problem with the UI if they installed ZeroTier, then uninstalled it, then installed again. This is now fixed. - UPnP port mappings should work better on some routers, and a different local port is now used for UPnP mapped traffic vs. NAT-t'd traffic to get around a bug in several popular mid-tier routers where using UPnP mapping alongside traditional NAT traversal made a port unreachable. - Debian package now builds with the right arch label on armv7l systems (Pi 2) - The old "root topology" has been replaced with a similar but better thought out concept called a World. The World defines the root servers and possibly in the future other things, and can be updated in-band from trusted peers allowing for software-upgrade-free network upgrades to keep up with growing demand. See node/World.hpp for details. - A fix was made to "self-awareness," which keeps track of your external IP info and adapts to changes, to eliminate a problem that could cause "link thrashing" behind some symmetric NATs. - Escalating UDP TTLs was re-introduced to better transit some port-restricted cone NATs such as Linux IP MASQ (used for Docker). - An otherwise harmless crash-on-exit bug in the network controller was fixed. - All new direct links are now confirmed in both directions. This adds a very small amount of initial HELLO/OK traffic but fixes some edge cases where an incomplete or unidirectional path might be used. - [SECURITY] Better rate limiting was put in place for VERB_PUSH_DIRECT_PATHS to prevent potential abuse for amplification attacks. - [SECURITY] Build flags were tweaked on OSX to ensure that all code including dependency libraries are built with full stack canary protection and ASLR support. Visit https://www.zerotier.com/blog or follow @ZeroTier on Twitter for updates and announcements! --- ext/installfiles/mac/postinst.sh | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/ext/installfiles/mac/postinst.sh b/ext/installfiles/mac/postinst.sh index 47d9ddd9..da15f9c8 100755 --- a/ext/installfiles/mac/postinst.sh +++ b/ext/installfiles/mac/postinst.sh @@ -2,9 +2,26 @@ 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 -- cgit v1.2.3 From 399b2e9e26bc2f5bae2f78cb41d8e977aa327bc9 Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Tue, 17 Nov 2015 19:16:10 -0800 Subject: forgot to submit this. Add DeferredPackets.cpp to the android makefile --- java/jni/Android.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/java/jni/Android.mk b/java/jni/Android.mk index 3da3b04b..5c2f1c79 100644 --- a/java/jni/Android.mk +++ b/java/jni/Android.mk @@ -15,6 +15,7 @@ LOCAL_SRC_FILES := \ $(ZT1)/ext/http-parser/http_parser.c \ $(ZT1)/node/C25519.cpp \ $(ZT1)/node/CertificateOfMembership.cpp \ + $(ZT1)/node/DeferredPackets.cpp \ $(ZT1)/node/Dictionary.cpp \ $(ZT1)/node/Identity.cpp \ $(ZT1)/node/IncomingPacket.cpp \ -- cgit v1.2.3 From 375aae44e4fd89d162b19749700a1e4ba17d5604 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 19 Nov 2015 16:36:15 -0800 Subject: . --- cluster-geo/cluster-geo/cluster-geo.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cluster-geo/cluster-geo/cluster-geo.js b/cluster-geo/cluster-geo/cluster-geo.js index 0dea22f2..3cbc60be 100644 --- a/cluster-geo/cluster-geo/cluster-geo.js +++ b/cluster-geo/cluster-geo/cluster-geo.js @@ -8,9 +8,9 @@ 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); +//var EventEmitter = require('events'); +//EventEmitter.prototype._maxListeners = 1000; +//process.setMaxListeners(1000); // Load config var config = require(__dirname + '/config.js'); -- cgit v1.2.3 From 1fde17bacb565bfc1536ef83276658e8bb6f0a0c Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 20 Nov 2015 11:46:10 -0800 Subject: Update World to reflect Alice and Bob in their final glory. Will hot-push this soon. --- world/mkworld.cpp | 42 ++++++++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/world/mkworld.cpp b/world/mkworld.cpp index 42a61723..551ba2fd 100644 --- a/world/mkworld.cpp +++ b/world/mkworld.cpp @@ -121,26 +121,48 @@ int main(int argc,char **argv) const uint64_t id = ZT_WORLD_ID_EARTH; const uint64_t ts = 1447696577275ULL; // November 16th, 2015 ~9:56AM + // 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 roots.push_back(World::Root()); roots.back().identity = Identity("7e19876aba:0:2a6e2b2318930f60eb097f70d0f4b028b2cd6d3d0c63c014b9039ff35390e41181f216fb2e6fa8d95c1ee9667156411905c3dccfea78d8c6dfafba688170b3fa"); roots.back().stableEndpoints.push_back(InetAddress("198.199.97.220/9993")); - // old EU-PARIS - roots.push_back(World::Root()); - roots.back().identity = Identity("8841408a2e:0:bb1d31f2c323e264e9e64172c1a74f77899555ed10751cd56e86405cde118d02dffe555d462ccf6a85b5631c12350c8d5dc409ba10b9025d0f445cf449d92b1c"); - roots.back().stableEndpoints.push_back(InetAddress("107.191.46.210/9993")); - // old US-NYC roots.push_back(World::Root()); roots.back().identity = Identity("8acf059fe3:0:482f6ee5dfe902319b419de5bdc765209c0ecda38c4d6e4fcf0d33658398b4527dcd22f93112fb9befd02fd78bf7261b333fc105d192a623ca9e50fc60b374a5"); roots.back().stableEndpoints.push_back(InetAddress("162.243.77.111/9993")); - // old AP-SNG - roots.push_back(World::Root()); - roots.back().identity = Identity("9d219039f3:0:01f0922a98e3b34ebcbff333269dc265d7a020aab69d72be4d4acc9c8c9294785771256cd1d942a90d1bd1d2dca3ea84ef7d85afe6611fb43ff0b74126d90a6e"); - roots.back().stableEndpoints.push_back(InetAddress("128.199.197.217/9993")); - // END WORLD DEFINITION // ========================================================================= -- cgit v1.2.3 From ce5b7f0305c40b649699110b0b5d16b23238acfa Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 20 Nov 2015 12:49:23 -0800 Subject: The World as of 2015-11-20 --- node/Topology.cpp | 9 +++++++-- world/earth-2015-11-20.bin | Bin 0 -> 792 bytes world/mkworld.cpp | 16 +++------------- 3 files changed, 10 insertions(+), 15 deletions(-) create mode 100644 world/earth-2015-11-20.bin diff --git a/node/Topology.cpp b/node/Topology.cpp index c7de22a8..d94975dd 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -35,8 +35,13 @@ namespace ZeroTier { -#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-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), diff --git a/world/earth-2015-11-20.bin b/world/earth-2015-11-20.bin new file mode 100644 index 00000000..198682e5 Binary files /dev/null and b/world/earth-2015-11-20.bin differ diff --git a/world/mkworld.cpp b/world/mkworld.cpp index 551ba2fd..a14aa55c 100644 --- a/world/mkworld.cpp +++ b/world/mkworld.cpp @@ -108,18 +108,8 @@ int main(int argc,char **argv) std::vector roots; - // - // The initial version of the World uses the old root server infrastructure. - // The new "Alice and Bob" infrastructure will replace this gradually, with - // Paris probably being the first node to be taken over and clusterized. - // - // ZeroTier does actual World generation on an air-gapped machine by copying - // this code over, building it there and running, then saving the results - // onto a USB key. - // - const uint64_t id = ZT_WORLD_ID_EARTH; - const uint64_t ts = 1447696577275ULL; // November 16th, 2015 ~9:56AM + const uint64_t ts = 1448048819338ULL; // November 20th, 2015 ~11:47AM // Alice roots.push_back(World::Root()); @@ -153,12 +143,12 @@ int main(int argc,char **argv) 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 + // 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 + // 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")); -- cgit v1.2.3 From ac09c3569a63d5cc9c5cc2c0b0cbd8cd7e68df20 Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Sat, 21 Nov 2015 19:14:06 -0800 Subject: ARP packet lengths are 28 bytes. This condition required the packet to be 29 or more bytes.
 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- osdep/Arp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osdep/Arp.cpp b/osdep/Arp.cpp index f71dfb54..2ca00f0d 100644 --- a/osdep/Arp.cpp +++ b/osdep/Arp.cpp @@ -65,7 +65,7 @@ uint32_t Arp::processIncomingArp(const void *arp,unsigned int len,void *response responseLen = 0; responseDest.zero(); - if (len > 28) { + if (len >= 28) { if (!memcmp(arp,ARP_REQUEST_HEADER,8)) { // Respond to ARP requests for locally-known IPs _ArpEntry *targetEntry = _cache.get(reinterpret_cast(arp)[6]); -- cgit v1.2.3 From 764dd1c3d94527c0870a913ac314b3b17eaea282 Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Sat, 21 Nov 2015 19:14:59 -0800 Subject: ARP packets do need the source IP address in them, as well as the MAC address. Packets wouldn't even show up in WireShark without the source IP in it. --- osdep/Arp.cpp | 11 ++++++----- osdep/Arp.hpp | 5 +++-- 2 files changed, 9 insertions(+), 7 deletions(-) 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(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 -- cgit v1.2.3