mirror of
https://github.com/tahoe-lafs/tahoe-lafs.git
synced 2024-12-23 23:02:25 +00:00
Merge branch 'master' into 3442.minor-test-runner-changes
This commit is contained in:
commit
784ddc5b07
44
docs/developer-guide.rst
Normal file
44
docs/developer-guide.rst
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
Developer Guide
|
||||||
|
===============
|
||||||
|
|
||||||
|
|
||||||
|
Pre-commit Checks
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
This project is configured for use with `pre-commit <https://pre-commit.com>`_ to perform some static code analysis checks. By default, pre-commit behavior is disabled. To enable pre-commit in a local checkout, first install pre-commit (consider using `pipx <https://pipxproject.github.io/pipx/>`_), then install the hooks with ``pre-commit install``.
|
||||||
|
|
||||||
|
For example::
|
||||||
|
|
||||||
|
tahoe-lafs $ pre-commit install
|
||||||
|
pre-commit installed at .git/hooks/pre-commit
|
||||||
|
tahoe-lafs $ python -c "import pathlib; pathlib.Path('src/allmydata/tabbed.py').write_text('def foo():\\n\\tpass\\n')"
|
||||||
|
tahoe-lafs $ git add src/allmydata/tabbed.py
|
||||||
|
tahoe-lafs $ git commit -a -m "Add a file that violates flake8"
|
||||||
|
flake8...................................................................Failed
|
||||||
|
- hook id: flake8
|
||||||
|
- exit code: 1
|
||||||
|
|
||||||
|
src/allmydata/tabbed.py:2:1: W191 indentation contains tabs
|
||||||
|
|
||||||
|
To uninstall::
|
||||||
|
|
||||||
|
tahoe-lafs $ pre-commit uninstall
|
||||||
|
pre-commit uninstalled
|
||||||
|
|
||||||
|
|
||||||
|
Some find running linters on every commit to be a nuisance. To avoid the checks triggering during commits, but to check before pushing to the CI, install the hook for pre-push instead::
|
||||||
|
|
||||||
|
tahoe-lafs $ pre-commit install -t pre-push
|
||||||
|
pre-commit installed at .git/hooks/pre-push
|
||||||
|
tahoe-lafs $ git commit -a -m "Add a file that violates flake8"
|
||||||
|
[3398.pre-commit 29f8f43d2] Add a file that violates flake8
|
||||||
|
1 file changed, 2 insertions(+)
|
||||||
|
create mode 100644 src/allmydata/tabbed.py
|
||||||
|
tahoe-lafs $ git push
|
||||||
|
flake8...................................................................Failed
|
||||||
|
- hook id: flake8
|
||||||
|
- exit code: 1
|
||||||
|
|
||||||
|
src/allmydata/tabbed.py:2:1: W191 indentation contains tabs
|
||||||
|
|
||||||
|
error: failed to push some refs to 'github.com:jaraco/tahoe-lafs.git'
|
@ -39,6 +39,8 @@ Contents:
|
|||||||
write_coordination
|
write_coordination
|
||||||
backupdb
|
backupdb
|
||||||
|
|
||||||
|
developer-guide
|
||||||
|
|
||||||
anonymity-configuration
|
anonymity-configuration
|
||||||
|
|
||||||
nodekeys
|
nodekeys
|
||||||
|
43
misc/python3/audit-dict-for-loops.py
Normal file
43
misc/python3/audit-dict-for-loops.py
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
"""
|
||||||
|
The following code is valid in Python 2:
|
||||||
|
|
||||||
|
for x in my_dict.keys():
|
||||||
|
if something(x):
|
||||||
|
del my_dict[x]
|
||||||
|
|
||||||
|
But broken in Python 3.
|
||||||
|
|
||||||
|
One solution is:
|
||||||
|
|
||||||
|
for x in list(my_dict.keys()):
|
||||||
|
if something(x):
|
||||||
|
del my_dict[x]
|
||||||
|
|
||||||
|
Some but not all code in Tahoe has been changed to that. In other cases, the code was left unchanged since there was no `del`.
|
||||||
|
|
||||||
|
However, some mistakes may have slept through.
|
||||||
|
|
||||||
|
To help catch cases that were incorrectly ported, this script runs futurize on all ported modules, which should convert it into the `list()` form.
|
||||||
|
You can then look at git diffs to see if any of the impacted would be buggy without the newly added `list()`.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
from subprocess import check_call
|
||||||
|
|
||||||
|
from allmydata.util import _python3
|
||||||
|
|
||||||
|
|
||||||
|
def fix_potential_issue():
|
||||||
|
for module in _python3.PORTED_MODULES + _python3.PORTED_TEST_MODULES:
|
||||||
|
filename = "src/" + module.replace(".", "/") + ".py"
|
||||||
|
if not os.path.exists(filename):
|
||||||
|
# Package, probably
|
||||||
|
filename = "src/" + module.replace(".", "/") + "/__init__.py"
|
||||||
|
check_call(["futurize", "-f", "lib2to3.fixes.fix_dict", "-w", filename])
|
||||||
|
print(
|
||||||
|
"All loops converted. Check diff to see if there are any that need to be commitedd."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
fix_potential_issue()
|
0
newsfragments/3382.minor
Normal file
0
newsfragments/3382.minor
Normal file
1
newsfragments/3398.minor
Normal file
1
newsfragments/3398.minor
Normal file
@ -0,0 +1 @@
|
|||||||
|
Added pre-commit config to run flake8 checks on commit/push.
|
0
newsfragments/3417.minor
Normal file
0
newsfragments/3417.minor
Normal file
0
newsfragments/3427.minor
Normal file
0
newsfragments/3427.minor
Normal file
0
newsfragments/3430.minor
Normal file
0
newsfragments/3430.minor
Normal file
0
newsfragments/3431.minor
Normal file
0
newsfragments/3431.minor
Normal file
0
newsfragments/3436.minor
Normal file
0
newsfragments/3436.minor
Normal file
0
newsfragments/3437.minor
Normal file
0
newsfragments/3437.minor
Normal file
0
newsfragments/3438.minor
Normal file
0
newsfragments/3438.minor
Normal file
0
newsfragments/3439.minor
Normal file
0
newsfragments/3439.minor
Normal file
0
newsfragments/3440.minor
Normal file
0
newsfragments/3440.minor
Normal file
0
newsfragments/3443.minor
Normal file
0
newsfragments/3443.minor
Normal file
0
newsfragments/3446.minor
Normal file
0
newsfragments/3446.minor
Normal file
0
newsfragments/3449.minor
Normal file
0
newsfragments/3449.minor
Normal file
@ -464,7 +464,7 @@ class Share(object):
|
|||||||
# there was corruption somewhere in the given range
|
# there was corruption somewhere in the given range
|
||||||
reason = "corruption in share[%d-%d): %s" % (start, start+offset,
|
reason = "corruption in share[%d-%d): %s" % (start, start+offset,
|
||||||
str(f.value))
|
str(f.value))
|
||||||
self._rref.callRemoteOnly("advise_corrupt_share", reason)
|
self._rref.callRemoteOnly("advise_corrupt_share", reason.encode("utf-8"))
|
||||||
|
|
||||||
def _satisfy_block_hash_tree(self, needed_hashes):
|
def _satisfy_block_hash_tree(self, needed_hashes):
|
||||||
o_bh = self.actual_offsets["block_hashes"]
|
o_bh = self.actual_offsets["block_hashes"]
|
||||||
|
@ -203,7 +203,7 @@ class CHKUploadHelper(Referenceable, upload.CHKUploader):
|
|||||||
def _finished(self, ur):
|
def _finished(self, ur):
|
||||||
assert interfaces.IUploadResults.providedBy(ur), ur
|
assert interfaces.IUploadResults.providedBy(ur), ur
|
||||||
vcapstr = ur.get_verifycapstr()
|
vcapstr = ur.get_verifycapstr()
|
||||||
precondition(isinstance(vcapstr, str), vcapstr)
|
precondition(isinstance(vcapstr, bytes), vcapstr)
|
||||||
v = uri.from_string(vcapstr)
|
v = uri.from_string(vcapstr)
|
||||||
f_times = self._fetcher.get_times()
|
f_times = self._fetcher.get_times()
|
||||||
|
|
||||||
@ -492,9 +492,9 @@ class Helper(Referenceable):
|
|||||||
# helper at random.
|
# helper at random.
|
||||||
|
|
||||||
name = "helper"
|
name = "helper"
|
||||||
VERSION = { "http://allmydata.org/tahoe/protocols/helper/v1" :
|
VERSION = { b"http://allmydata.org/tahoe/protocols/helper/v1" :
|
||||||
{ },
|
{ },
|
||||||
"application-version": str(allmydata.__full_version__),
|
b"application-version": allmydata.__full_version__.encode("utf-8"),
|
||||||
}
|
}
|
||||||
MAX_UPLOAD_STATUSES = 10
|
MAX_UPLOAD_STATUSES = 10
|
||||||
|
|
||||||
|
@ -299,7 +299,7 @@ class ServerTracker(object):
|
|||||||
I abort the remote bucket writers for all shares. This is a good idea
|
I abort the remote bucket writers for all shares. This is a good idea
|
||||||
to conserve space on the storage server.
|
to conserve space on the storage server.
|
||||||
"""
|
"""
|
||||||
self.abort_some_buckets(self.buckets.keys())
|
self.abort_some_buckets(list(self.buckets.keys()))
|
||||||
|
|
||||||
def abort_some_buckets(self, sharenums):
|
def abort_some_buckets(self, sharenums):
|
||||||
"""
|
"""
|
||||||
@ -1816,15 +1816,15 @@ class Uploader(service.MultiService, log.PrefixingLogMixin):
|
|||||||
|
|
||||||
def _got_helper(self, helper):
|
def _got_helper(self, helper):
|
||||||
self.log("got helper connection, getting versions")
|
self.log("got helper connection, getting versions")
|
||||||
default = { "http://allmydata.org/tahoe/protocols/helper/v1" :
|
default = { b"http://allmydata.org/tahoe/protocols/helper/v1" :
|
||||||
{ },
|
{ },
|
||||||
"application-version": "unknown: no get_version()",
|
b"application-version": b"unknown: no get_version()",
|
||||||
}
|
}
|
||||||
d = add_version_to_remote_reference(helper, default)
|
d = add_version_to_remote_reference(helper, default)
|
||||||
d.addCallback(self._got_versioned_helper)
|
d.addCallback(self._got_versioned_helper)
|
||||||
|
|
||||||
def _got_versioned_helper(self, helper):
|
def _got_versioned_helper(self, helper):
|
||||||
needed = "http://allmydata.org/tahoe/protocols/helper/v1"
|
needed = b"http://allmydata.org/tahoe/protocols/helper/v1"
|
||||||
if needed not in helper.version:
|
if needed not in helper.version:
|
||||||
raise InsufficientVersionError(needed, helper.version)
|
raise InsufficientVersionError(needed, helper.version)
|
||||||
self._helper = helper
|
self._helper = helper
|
||||||
|
@ -2,13 +2,15 @@
|
|||||||
Interfaces for Tahoe-LAFS.
|
Interfaces for Tahoe-LAFS.
|
||||||
|
|
||||||
Ported to Python 3.
|
Ported to Python 3.
|
||||||
|
|
||||||
|
Note that for RemoteInterfaces, the __remote_name__ needs to be a native string because of https://github.com/warner/foolscap/blob/43f4485a42c9c28e2c79d655b3a9e24d4e6360ca/src/foolscap/remoteinterface.py#L67
|
||||||
"""
|
"""
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
from __future__ import division
|
from __future__ import division
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from future.utils import PY2
|
from future.utils import PY2, native_str
|
||||||
if PY2:
|
if PY2:
|
||||||
# Don't import object/str/dict/etc. types, so we don't break any
|
# Don't import object/str/dict/etc. types, so we don't break any
|
||||||
# interfaces. Not importing open() because it triggers bogus flake8 error.
|
# interfaces. Not importing open() because it triggers bogus flake8 error.
|
||||||
@ -105,7 +107,7 @@ ReadData = ListOf(ShareData)
|
|||||||
|
|
||||||
|
|
||||||
class RIStorageServer(RemoteInterface):
|
class RIStorageServer(RemoteInterface):
|
||||||
__remote_name__ = b"RIStorageServer.tahoe.allmydata.com"
|
__remote_name__ = native_str("RIStorageServer.tahoe.allmydata.com")
|
||||||
|
|
||||||
def get_version():
|
def get_version():
|
||||||
"""
|
"""
|
||||||
@ -2836,17 +2838,17 @@ class RIControlClient(RemoteInterface):
|
|||||||
|
|
||||||
# debug stuff
|
# debug stuff
|
||||||
|
|
||||||
def upload_random_data_from_file(size=int, convergence=str):
|
def upload_random_data_from_file(size=int, convergence=bytes):
|
||||||
return str
|
return str
|
||||||
|
|
||||||
def download_to_tempfile_and_delete(uri=str):
|
def download_to_tempfile_and_delete(uri=bytes):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_memory_usage():
|
def get_memory_usage():
|
||||||
"""Return a dict describes the amount of memory currently in use. The
|
"""Return a dict describes the amount of memory currently in use. The
|
||||||
keys are 'VmPeak', 'VmSize', and 'VmData'. The values are integers,
|
keys are 'VmPeak', 'VmSize', and 'VmData'. The values are integers,
|
||||||
measuring memory consupmtion in bytes."""
|
measuring memory consupmtion in bytes."""
|
||||||
return DictOf(str, int)
|
return DictOf(bytes, int)
|
||||||
|
|
||||||
def speed_test(count=int, size=int, mutable=Any()):
|
def speed_test(count=int, size=int, mutable=Any()):
|
||||||
"""Write 'count' tempfiles to disk, all of the given size. Measure
|
"""Write 'count' tempfiles to disk, all of the given size. Measure
|
||||||
@ -2871,11 +2873,11 @@ class RIControlClient(RemoteInterface):
|
|||||||
return DictOf(str, float)
|
return DictOf(str, float)
|
||||||
|
|
||||||
|
|
||||||
UploadResults = Any() #DictOf(str, str)
|
UploadResults = Any() #DictOf(bytes, bytes)
|
||||||
|
|
||||||
|
|
||||||
class RIEncryptedUploadable(RemoteInterface):
|
class RIEncryptedUploadable(RemoteInterface):
|
||||||
__remote_name__ = b"RIEncryptedUploadable.tahoe.allmydata.com"
|
__remote_name__ = native_str("RIEncryptedUploadable.tahoe.allmydata.com")
|
||||||
|
|
||||||
def get_size():
|
def get_size():
|
||||||
return Offset
|
return Offset
|
||||||
@ -2884,33 +2886,33 @@ class RIEncryptedUploadable(RemoteInterface):
|
|||||||
return (int, int, int, long)
|
return (int, int, int, long)
|
||||||
|
|
||||||
def read_encrypted(offset=Offset, length=ReadSize):
|
def read_encrypted(offset=Offset, length=ReadSize):
|
||||||
return ListOf(str)
|
return ListOf(bytes)
|
||||||
|
|
||||||
def close():
|
def close():
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
class RICHKUploadHelper(RemoteInterface):
|
class RICHKUploadHelper(RemoteInterface):
|
||||||
__remote_name__ = b"RIUploadHelper.tahoe.allmydata.com"
|
__remote_name__ = native_str("RIUploadHelper.tahoe.allmydata.com")
|
||||||
|
|
||||||
def get_version():
|
def get_version():
|
||||||
"""
|
"""
|
||||||
Return a dictionary of version information.
|
Return a dictionary of version information.
|
||||||
"""
|
"""
|
||||||
return DictOf(str, Any())
|
return DictOf(bytes, Any())
|
||||||
|
|
||||||
def upload(reader=RIEncryptedUploadable):
|
def upload(reader=RIEncryptedUploadable):
|
||||||
return UploadResults
|
return UploadResults
|
||||||
|
|
||||||
|
|
||||||
class RIHelper(RemoteInterface):
|
class RIHelper(RemoteInterface):
|
||||||
__remote_name__ = b"RIHelper.tahoe.allmydata.com"
|
__remote_name__ = native_str("RIHelper.tahoe.allmydata.com")
|
||||||
|
|
||||||
def get_version():
|
def get_version():
|
||||||
"""
|
"""
|
||||||
Return a dictionary of version information.
|
Return a dictionary of version information.
|
||||||
"""
|
"""
|
||||||
return DictOf(str, Any())
|
return DictOf(bytes, Any())
|
||||||
|
|
||||||
def upload_chk(si=StorageIndex):
|
def upload_chk(si=StorageIndex):
|
||||||
"""See if a file with a given storage index needs uploading. The
|
"""See if a file with a given storage index needs uploading. The
|
||||||
@ -2931,7 +2933,7 @@ class RIHelper(RemoteInterface):
|
|||||||
|
|
||||||
|
|
||||||
class RIStatsProvider(RemoteInterface):
|
class RIStatsProvider(RemoteInterface):
|
||||||
__remote_name__ = b"RIStatsProvider.tahoe.allmydata.com"
|
__remote_name__ = native_str("RIStatsProvider.tahoe.allmydata.com")
|
||||||
"""
|
"""
|
||||||
Provides access to statistics and monitoring information.
|
Provides access to statistics and monitoring information.
|
||||||
"""
|
"""
|
||||||
@ -2944,16 +2946,16 @@ class RIStatsProvider(RemoteInterface):
|
|||||||
stats are instantaneous measures (potentially time averaged
|
stats are instantaneous measures (potentially time averaged
|
||||||
internally)
|
internally)
|
||||||
"""
|
"""
|
||||||
return DictOf(str, DictOf(str, ChoiceOf(float, int, long, None)))
|
return DictOf(bytes, DictOf(bytes, ChoiceOf(float, int, long, None)))
|
||||||
|
|
||||||
|
|
||||||
class RIStatsGatherer(RemoteInterface):
|
class RIStatsGatherer(RemoteInterface):
|
||||||
__remote_name__ = b"RIStatsGatherer.tahoe.allmydata.com"
|
__remote_name__ = native_str("RIStatsGatherer.tahoe.allmydata.com")
|
||||||
"""
|
"""
|
||||||
Provides a monitoring service for centralised collection of stats
|
Provides a monitoring service for centralised collection of stats
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def provide(provider=RIStatsProvider, nickname=str):
|
def provide(provider=RIStatsProvider, nickname=bytes):
|
||||||
"""
|
"""
|
||||||
@param provider: a stats collector instance that should be polled
|
@param provider: a stats collector instance that should be polled
|
||||||
periodically by the gatherer to collect stats.
|
periodically by the gatherer to collect stats.
|
||||||
@ -2965,7 +2967,7 @@ class RIStatsGatherer(RemoteInterface):
|
|||||||
class IStatsProducer(Interface):
|
class IStatsProducer(Interface):
|
||||||
def get_stats():
|
def get_stats():
|
||||||
"""
|
"""
|
||||||
returns a dictionary, with str keys representing the names of stats
|
returns a dictionary, with bytes keys representing the names of stats
|
||||||
to be monitored, and numeric values.
|
to be monitored, and numeric values.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -1,3 +1,16 @@
|
|||||||
|
"""
|
||||||
|
Ported to Python 3.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import division
|
||||||
|
from __future__ import print_function
|
||||||
|
|
||||||
|
from future.utils import PY2, native_str
|
||||||
|
if PY2:
|
||||||
|
# Omitted types (bytes etc.) so future variants don't confuse Foolscap.
|
||||||
|
from future.builtins import filter, map, zip, ascii, chr, hex, input, next, oct, open, pow, round, super, object, range, max, min # noqa: F401
|
||||||
|
|
||||||
from zope.interface import Interface
|
from zope.interface import Interface
|
||||||
from foolscap.api import StringConstraint, SetOf, DictOf, Any, \
|
from foolscap.api import StringConstraint, SetOf, DictOf, Any, \
|
||||||
@ -11,8 +24,8 @@ FURL = StringConstraint(1000)
|
|||||||
# "app-versions", "my-version", "oldest-supported", and "service-name".
|
# "app-versions", "my-version", "oldest-supported", and "service-name".
|
||||||
# Plus service-specific keys like "anonymous-storage-FURL" and
|
# Plus service-specific keys like "anonymous-storage-FURL" and
|
||||||
# "permutation-seed-base32" (both for service="storage").
|
# "permutation-seed-base32" (both for service="storage").
|
||||||
# * sig_vs (str): "v0-"+base32(signature(msg))
|
# * sig_vs (bytes): "v0-"+base32(signature(msg))
|
||||||
# * claimed_key_vs (str): "v0-"+base32(pubkey)
|
# * claimed_key_vs (bytes): "v0-"+base32(pubkey)
|
||||||
|
|
||||||
# (nickname, my_version, oldest_supported) refer to the client as a whole.
|
# (nickname, my_version, oldest_supported) refer to the client as a whole.
|
||||||
# The my_version/oldest_supported strings can be parsed by an
|
# The my_version/oldest_supported strings can be parsed by an
|
||||||
@ -28,26 +41,26 @@ FURL = StringConstraint(1000)
|
|||||||
Announcement_v2 = Any()
|
Announcement_v2 = Any()
|
||||||
|
|
||||||
class RIIntroducerSubscriberClient_v2(RemoteInterface):
|
class RIIntroducerSubscriberClient_v2(RemoteInterface):
|
||||||
__remote_name__ = "RIIntroducerSubscriberClient_v2.tahoe.allmydata.com"
|
__remote_name__ = native_str("RIIntroducerSubscriberClient_v2.tahoe.allmydata.com")
|
||||||
|
|
||||||
def announce_v2(announcements=SetOf(Announcement_v2)):
|
def announce_v2(announcements=SetOf(Announcement_v2)):
|
||||||
"""I accept announcements from the publisher."""
|
"""I accept announcements from the publisher."""
|
||||||
return None
|
return None
|
||||||
|
|
||||||
SubscriberInfo = DictOf(str, Any())
|
SubscriberInfo = DictOf(bytes, Any())
|
||||||
|
|
||||||
class RIIntroducerPublisherAndSubscriberService_v2(RemoteInterface):
|
class RIIntroducerPublisherAndSubscriberService_v2(RemoteInterface):
|
||||||
"""To publish a service to the world, connect to me and give me your
|
"""To publish a service to the world, connect to me and give me your
|
||||||
announcement message. I will deliver a copy to all connected subscribers.
|
announcement message. I will deliver a copy to all connected subscribers.
|
||||||
To hear about services, connect to me and subscribe to a specific
|
To hear about services, connect to me and subscribe to a specific
|
||||||
service_name."""
|
service_name."""
|
||||||
__remote_name__ = "RIIntroducerPublisherAndSubscriberService_v2.tahoe.allmydata.com"
|
__remote_name__ = native_str("RIIntroducerPublisherAndSubscriberService_v2.tahoe.allmydata.com")
|
||||||
def get_version():
|
def get_version():
|
||||||
return DictOf(str, Any())
|
return DictOf(bytes, Any())
|
||||||
def publish_v2(announcement=Announcement_v2, canary=Referenceable):
|
def publish_v2(announcement=Announcement_v2, canary=Referenceable):
|
||||||
return None
|
return None
|
||||||
def subscribe_v2(subscriber=RIIntroducerSubscriberClient_v2,
|
def subscribe_v2(subscriber=RIIntroducerSubscriberClient_v2,
|
||||||
service_name=str, subscriber_info=SubscriberInfo):
|
service_name=bytes, subscriber_info=SubscriberInfo):
|
||||||
"""Give me a subscriber reference, and I will call its announce_v2()
|
"""Give me a subscriber reference, and I will call its announce_v2()
|
||||||
method with any announcements that match the desired service name. I
|
method with any announcements that match the desired service name. I
|
||||||
will ignore duplicate subscriptions. The subscriber_info dictionary
|
will ignore duplicate subscriptions. The subscriber_info dictionary
|
||||||
@ -93,11 +106,16 @@ class IIntroducerClient(Interface):
|
|||||||
version: 0
|
version: 0
|
||||||
nickname: unicode
|
nickname: unicode
|
||||||
app-versions: {}
|
app-versions: {}
|
||||||
my-version: str
|
my-version: bytes
|
||||||
oldest-supported: str
|
oldest-supported: bytes
|
||||||
|
|
||||||
service-name: str('storage')
|
service-name: bytes('storage')
|
||||||
anonymous-storage-FURL: str(furl)
|
anonymous-storage-FURL: bytes(furl)
|
||||||
|
|
||||||
|
In order to be JSON-serializable, all byte strings are assumed to be
|
||||||
|
ASCII-encoded, and the receiver can therefore decode them into Unicode
|
||||||
|
strings if they wish. Representation of these fields elsewhere in Tahoe
|
||||||
|
may differ, e.g. by being unicode strings.
|
||||||
|
|
||||||
Note that app-version will be an empty dictionary if either the
|
Note that app-version will be an empty dictionary if either the
|
||||||
publishing client or the Introducer are running older code.
|
publishing client or the Introducer are running older code.
|
||||||
|
@ -280,13 +280,14 @@ class MutableFileNode(object):
|
|||||||
|
|
||||||
def __hash__(self):
|
def __hash__(self):
|
||||||
return hash((self.__class__, self._uri))
|
return hash((self.__class__, self._uri))
|
||||||
def __cmp__(self, them):
|
|
||||||
if cmp(type(self), type(them)):
|
|
||||||
return cmp(type(self), type(them))
|
|
||||||
if cmp(self.__class__, them.__class__):
|
|
||||||
return cmp(self.__class__, them.__class__)
|
|
||||||
return cmp(self._uri, them._uri)
|
|
||||||
|
|
||||||
|
def __eq__(self, them):
|
||||||
|
if type(self) != type(them):
|
||||||
|
return False
|
||||||
|
return self._uri == them._uri
|
||||||
|
|
||||||
|
def __ne__(self, them):
|
||||||
|
return not (self == them)
|
||||||
|
|
||||||
#################################
|
#################################
|
||||||
# ICheckable
|
# ICheckable
|
||||||
@ -946,7 +947,7 @@ class MutableFileVersion(object):
|
|||||||
"""
|
"""
|
||||||
c = consumer.MemoryConsumer(progress=progress)
|
c = consumer.MemoryConsumer(progress=progress)
|
||||||
d = self.read(c, fetch_privkey=fetch_privkey)
|
d = self.read(c, fetch_privkey=fetch_privkey)
|
||||||
d.addCallback(lambda mc: "".join(mc.chunks))
|
d.addCallback(lambda mc: b"".join(mc.chunks))
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ class RetrieveStatus(object):
|
|||||||
self.size = None
|
self.size = None
|
||||||
self.status = "Not started"
|
self.status = "Not started"
|
||||||
self.progress = 0.0
|
self.progress = 0.0
|
||||||
self.counter = self.statusid_counter.next()
|
self.counter = next(self.statusid_counter)
|
||||||
self.started = time.time()
|
self.started = time.time()
|
||||||
|
|
||||||
def get_started(self):
|
def get_started(self):
|
||||||
@ -321,7 +321,7 @@ class Retrieve(object):
|
|||||||
self._active_readers = [] # list of active readers for this dl.
|
self._active_readers = [] # list of active readers for this dl.
|
||||||
self._block_hash_trees = {} # shnum => hashtree
|
self._block_hash_trees = {} # shnum => hashtree
|
||||||
|
|
||||||
for i in xrange(self._total_shares):
|
for i in range(self._total_shares):
|
||||||
# So we don't have to do this later.
|
# So we don't have to do this later.
|
||||||
self._block_hash_trees[i] = hashtree.IncompleteHashTree(self._num_segments)
|
self._block_hash_trees[i] = hashtree.IncompleteHashTree(self._num_segments)
|
||||||
|
|
||||||
@ -743,7 +743,7 @@ class Retrieve(object):
|
|||||||
|
|
||||||
block_and_salt, blockhashes, sharehashes = results
|
block_and_salt, blockhashes, sharehashes = results
|
||||||
block, salt = block_and_salt
|
block, salt = block_and_salt
|
||||||
_assert(type(block) is str, (block, salt))
|
_assert(isinstance(block, bytes), (block, salt))
|
||||||
|
|
||||||
blockhashes = dict(enumerate(blockhashes))
|
blockhashes = dict(enumerate(blockhashes))
|
||||||
self.log("the reader gave me the following blockhashes: %s" % \
|
self.log("the reader gave me the following blockhashes: %s" % \
|
||||||
@ -847,7 +847,7 @@ class Retrieve(object):
|
|||||||
# d.items()[0] is like (shnum, (block, salt))
|
# d.items()[0] is like (shnum, (block, salt))
|
||||||
# d.items()[0][1] is like (block, salt)
|
# d.items()[0][1] is like (block, salt)
|
||||||
# d.items()[0][1][1] is the salt.
|
# d.items()[0][1][1] is the salt.
|
||||||
salt = blocks_and_salts.items()[0][1][1]
|
salt = list(blocks_and_salts.items())[0][1][1]
|
||||||
# Next, extract just the blocks from the dict. We'll use the
|
# Next, extract just the blocks from the dict. We'll use the
|
||||||
# salt in the next step.
|
# salt in the next step.
|
||||||
share_and_shareids = [(k, v[0]) for k, v in blocks_and_salts.items()]
|
share_and_shareids = [(k, v[0]) for k, v in blocks_and_salts.items()]
|
||||||
@ -870,7 +870,7 @@ class Retrieve(object):
|
|||||||
else:
|
else:
|
||||||
d = defer.maybeDeferred(self._segment_decoder.decode, shares, shareids)
|
d = defer.maybeDeferred(self._segment_decoder.decode, shares, shareids)
|
||||||
def _process(buffers):
|
def _process(buffers):
|
||||||
segment = "".join(buffers)
|
segment = b"".join(buffers)
|
||||||
self.log(format="now decoding segment %(segnum)s of %(numsegs)s",
|
self.log(format="now decoding segment %(segnum)s of %(numsegs)s",
|
||||||
segnum=segnum,
|
segnum=segnum,
|
||||||
numsegs=self._num_segments,
|
numsegs=self._num_segments,
|
||||||
|
@ -33,7 +33,7 @@ class UpdateStatus(object):
|
|||||||
self.mode = "?"
|
self.mode = "?"
|
||||||
self.status = "Not started"
|
self.status = "Not started"
|
||||||
self.progress = 0.0
|
self.progress = 0.0
|
||||||
self.counter = self.statusid_counter.next()
|
self.counter = next(self.statusid_counter)
|
||||||
self.started = time.time()
|
self.started = time.time()
|
||||||
self.finished = None
|
self.finished = None
|
||||||
|
|
||||||
|
@ -697,7 +697,7 @@ class StorageServer(service.MultiService, Referenceable):
|
|||||||
# This is a remote API, I believe, so this has to be bytes for legacy
|
# This is a remote API, I believe, so this has to be bytes for legacy
|
||||||
# protocol backwards compatibility reasons.
|
# protocol backwards compatibility reasons.
|
||||||
assert isinstance(share_type, bytes)
|
assert isinstance(share_type, bytes)
|
||||||
assert isinstance(reason, bytes)
|
assert isinstance(reason, bytes), "%r is not bytes" % (reason,)
|
||||||
fileutil.make_dirs(self.corruption_advisory_dir)
|
fileutil.make_dirs(self.corruption_advisory_dir)
|
||||||
now = time_format.iso_utc(sep="T")
|
now = time_format.iso_utc(sep="T")
|
||||||
si_s = si_b2a(storage_index)
|
si_s = si_b2a(storage_index)
|
||||||
|
@ -28,6 +28,7 @@ the foolscap-based server implemented in src/allmydata/storage/*.py .
|
|||||||
#
|
#
|
||||||
# 6: implement other sorts of IStorageClient classes: S3, etc
|
# 6: implement other sorts of IStorageClient classes: S3, etc
|
||||||
|
|
||||||
|
from past.builtins import unicode
|
||||||
|
|
||||||
import re, time, hashlib
|
import re, time, hashlib
|
||||||
try:
|
try:
|
||||||
@ -489,12 +490,15 @@ class _FoolscapStorage(object):
|
|||||||
|
|
||||||
*nickname* is optional.
|
*nickname* is optional.
|
||||||
"""
|
"""
|
||||||
m = re.match(r'pb://(\w+)@', furl)
|
m = re.match(br'pb://(\w+)@', furl)
|
||||||
assert m, furl
|
assert m, furl
|
||||||
tubid_s = m.group(1).lower()
|
tubid_s = m.group(1).lower()
|
||||||
tubid = base32.a2b(tubid_s)
|
tubid = base32.a2b(tubid_s)
|
||||||
if "permutation-seed-base32" in ann:
|
if "permutation-seed-base32" in ann:
|
||||||
ps = base32.a2b(str(ann["permutation-seed-base32"]))
|
seed = ann["permutation-seed-base32"]
|
||||||
|
if isinstance(seed, unicode):
|
||||||
|
seed = seed.encode("utf-8")
|
||||||
|
ps = base32.a2b(seed)
|
||||||
elif re.search(r'^v0-[0-9a-zA-Z]{52}$', server_id):
|
elif re.search(r'^v0-[0-9a-zA-Z]{52}$', server_id):
|
||||||
ps = base32.a2b(server_id[3:])
|
ps = base32.a2b(server_id[3:])
|
||||||
else:
|
else:
|
||||||
@ -509,7 +513,7 @@ class _FoolscapStorage(object):
|
|||||||
|
|
||||||
assert server_id
|
assert server_id
|
||||||
long_description = server_id
|
long_description = server_id
|
||||||
if server_id.startswith("v0-"):
|
if server_id.startswith(b"v0-"):
|
||||||
# remove v0- prefix from abbreviated name
|
# remove v0- prefix from abbreviated name
|
||||||
short_description = server_id[3:3+8]
|
short_description = server_id[3:3+8]
|
||||||
else:
|
else:
|
||||||
@ -621,19 +625,19 @@ class NativeStorageServer(service.MultiService):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
VERSION_DEFAULTS = {
|
VERSION_DEFAULTS = {
|
||||||
"http://allmydata.org/tahoe/protocols/storage/v1" :
|
b"http://allmydata.org/tahoe/protocols/storage/v1" :
|
||||||
{ "maximum-immutable-share-size": 2**32 - 1,
|
{ b"maximum-immutable-share-size": 2**32 - 1,
|
||||||
"maximum-mutable-share-size": 2*1000*1000*1000, # maximum prior to v1.9.2
|
b"maximum-mutable-share-size": 2*1000*1000*1000, # maximum prior to v1.9.2
|
||||||
"tolerates-immutable-read-overrun": False,
|
b"tolerates-immutable-read-overrun": False,
|
||||||
"delete-mutable-shares-with-zero-length-writev": False,
|
b"delete-mutable-shares-with-zero-length-writev": False,
|
||||||
"available-space": None,
|
b"available-space": None,
|
||||||
},
|
},
|
||||||
"application-version": "unknown: no get_version()",
|
b"application-version": "unknown: no get_version()",
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, server_id, ann, tub_maker, handler_overrides, node_config, config=StorageClientConfig()):
|
def __init__(self, server_id, ann, tub_maker, handler_overrides, node_config, config=StorageClientConfig()):
|
||||||
service.MultiService.__init__(self)
|
service.MultiService.__init__(self)
|
||||||
assert isinstance(server_id, str)
|
assert isinstance(server_id, bytes)
|
||||||
self._server_id = server_id
|
self._server_id = server_id
|
||||||
self.announcement = ann
|
self.announcement = ann
|
||||||
self._tub_maker = tub_maker
|
self._tub_maker = tub_maker
|
||||||
@ -694,12 +698,14 @@ class NativeStorageServer(service.MultiService):
|
|||||||
# Nope
|
# Nope
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
|
if isinstance(furl, unicode):
|
||||||
|
furl = furl.encode("utf-8")
|
||||||
# See comment above for the _storage_from_foolscap_plugin case
|
# See comment above for the _storage_from_foolscap_plugin case
|
||||||
# about passing in get_rref.
|
# about passing in get_rref.
|
||||||
storage_server = _StorageServer(get_rref=self.get_rref)
|
storage_server = _StorageServer(get_rref=self.get_rref)
|
||||||
return _FoolscapStorage.from_announcement(
|
return _FoolscapStorage.from_announcement(
|
||||||
self._server_id,
|
self._server_id,
|
||||||
furl.encode("utf-8"),
|
furl,
|
||||||
ann,
|
ann,
|
||||||
storage_server,
|
storage_server,
|
||||||
)
|
)
|
||||||
@ -767,7 +773,7 @@ class NativeStorageServer(service.MultiService):
|
|||||||
version = self.get_version()
|
version = self.get_version()
|
||||||
if version is None:
|
if version is None:
|
||||||
return None
|
return None
|
||||||
protocol_v1_version = version.get('http://allmydata.org/tahoe/protocols/storage/v1', {})
|
protocol_v1_version = version.get(b'http://allmydata.org/tahoe/protocols/storage/v1', {})
|
||||||
available_space = protocol_v1_version.get('available-space')
|
available_space = protocol_v1_version.get('available-space')
|
||||||
if available_space is None:
|
if available_space is None:
|
||||||
available_space = protocol_v1_version.get('maximum-immutable-share-size', None)
|
available_space = protocol_v1_version.get('maximum-immutable-share-size', None)
|
||||||
|
@ -781,7 +781,7 @@ def create_mutable_filenode(contents, mdmf=False, all_contents=None):
|
|||||||
return filenode
|
return filenode
|
||||||
|
|
||||||
|
|
||||||
TEST_DATA="\x02"*(Uploader.URI_LIT_SIZE_THRESHOLD+1)
|
TEST_DATA=b"\x02"*(Uploader.URI_LIT_SIZE_THRESHOLD+1)
|
||||||
|
|
||||||
|
|
||||||
class WebErrorMixin(object):
|
class WebErrorMixin(object):
|
||||||
@ -958,12 +958,12 @@ def _corrupt_offset_of_block_hashes_to_truncate_crypttext_hashes(data, debug=Fal
|
|||||||
assert sharevernum in (1, 2), "This test is designed to corrupt immutable shares of v1 or v2 in specific ways."
|
assert sharevernum in (1, 2), "This test is designed to corrupt immutable shares of v1 or v2 in specific ways."
|
||||||
if sharevernum == 1:
|
if sharevernum == 1:
|
||||||
curval = struct.unpack(">L", data[0x0c+0x18:0x0c+0x18+4])[0]
|
curval = struct.unpack(">L", data[0x0c+0x18:0x0c+0x18+4])[0]
|
||||||
newval = random.randrange(0, max(1, (curval/hashutil.CRYPTO_VAL_SIZE)/2))*hashutil.CRYPTO_VAL_SIZE
|
newval = random.randrange(0, max(1, (curval//hashutil.CRYPTO_VAL_SIZE)//2))*hashutil.CRYPTO_VAL_SIZE
|
||||||
newvalstr = struct.pack(">L", newval)
|
newvalstr = struct.pack(">L", newval)
|
||||||
return data[:0x0c+0x18]+newvalstr+data[0x0c+0x18+4:]
|
return data[:0x0c+0x18]+newvalstr+data[0x0c+0x18+4:]
|
||||||
else:
|
else:
|
||||||
curval = struct.unpack(">Q", data[0x0c+0x2c:0x0c+0x2c+8])[0]
|
curval = struct.unpack(">Q", data[0x0c+0x2c:0x0c+0x2c+8])[0]
|
||||||
newval = random.randrange(0, max(1, (curval/hashutil.CRYPTO_VAL_SIZE)/2))*hashutil.CRYPTO_VAL_SIZE
|
newval = random.randrange(0, max(1, (curval//hashutil.CRYPTO_VAL_SIZE)//2))*hashutil.CRYPTO_VAL_SIZE
|
||||||
newvalstr = struct.pack(">Q", newval)
|
newvalstr = struct.pack(">Q", newval)
|
||||||
return data[:0x0c+0x2c]+newvalstr+data[0x0c+0x2c+8:]
|
return data[:0x0c+0x2c]+newvalstr+data[0x0c+0x2c+8:]
|
||||||
|
|
||||||
|
@ -159,9 +159,12 @@ class FakeCanary(object):
|
|||||||
if self.ignore:
|
if self.ignore:
|
||||||
return
|
return
|
||||||
del self.disconnectors[marker]
|
del self.disconnectors[marker]
|
||||||
|
def getRemoteTubID(self):
|
||||||
|
return None
|
||||||
|
def getPeer(self):
|
||||||
|
return "<fake>"
|
||||||
|
|
||||||
|
|
||||||
class LoggingServiceParent(service.MultiService):
|
class LoggingServiceParent(service.MultiService):
|
||||||
def log(self, *args, **kwargs):
|
def log(self, *args, **kwargs):
|
||||||
return log.msg(*args, **kwargs)
|
return log.msg(*args, **kwargs)
|
||||||
|
|
||||||
|
@ -8,12 +8,10 @@ from twisted.internet import reactor, defer
|
|||||||
from twisted.trial import unittest
|
from twisted.trial import unittest
|
||||||
|
|
||||||
from ..util.assertutil import precondition
|
from ..util.assertutil import precondition
|
||||||
|
from ..scripts import runner
|
||||||
from allmydata.util.encodingutil import get_io_encoding
|
from allmydata.util.encodingutil import get_io_encoding
|
||||||
from future.utils import PY2
|
|
||||||
if PY2: # XXX this is a hack that makes some tests pass on Python3, remove
|
|
||||||
# in the future
|
|
||||||
from ..scripts import runner
|
|
||||||
# Imported for backwards compatibility:
|
# Imported for backwards compatibility:
|
||||||
|
from future.utils import bord, bchr, binary_type
|
||||||
from .common_py3 import (
|
from .common_py3 import (
|
||||||
SignalMixin, skip_if_cannot_represent_filename, ReallyEqualMixin, ShouldFailMixin
|
SignalMixin, skip_if_cannot_represent_filename, ReallyEqualMixin, ShouldFailMixin
|
||||||
)
|
)
|
||||||
@ -57,9 +55,10 @@ class DevNullDictionary(dict):
|
|||||||
return
|
return
|
||||||
|
|
||||||
def insecurerandstr(n):
|
def insecurerandstr(n):
|
||||||
return ''.join(map(chr, map(randrange, [0]*n, [256]*n)))
|
return b''.join(map(bchr, map(randrange, [0]*n, [256]*n)))
|
||||||
|
|
||||||
def flip_bit(good, which):
|
def flip_bit(good, which):
|
||||||
|
# TODO Probs need to update with bchr/bord as with flip_one_bit, below.
|
||||||
# flip the low-order bit of good[which]
|
# flip the low-order bit of good[which]
|
||||||
if which == -1:
|
if which == -1:
|
||||||
pieces = good[:which], good[-1:], ""
|
pieces = good[:which], good[-1:], ""
|
||||||
@ -70,10 +69,11 @@ def flip_bit(good, which):
|
|||||||
def flip_one_bit(s, offset=0, size=None):
|
def flip_one_bit(s, offset=0, size=None):
|
||||||
""" flip one random bit of the string s, in a byte greater than or equal to offset and less
|
""" flip one random bit of the string s, in a byte greater than or equal to offset and less
|
||||||
than offset+size. """
|
than offset+size. """
|
||||||
|
precondition(isinstance(s, binary_type))
|
||||||
if size is None:
|
if size is None:
|
||||||
size=len(s)-offset
|
size=len(s)-offset
|
||||||
i = randrange(offset, offset+size)
|
i = randrange(offset, offset+size)
|
||||||
result = s[:i] + chr(ord(s[i])^(0x01<<randrange(0, 8))) + s[i+1:]
|
result = s[:i] + bchr(bord(s[i])^(0x01<<randrange(0, 8))) + s[i+1:]
|
||||||
assert result != s, "Internal error -- flip_one_bit() produced the same string as its input: %s == %s" % (result, s)
|
assert result != s, "Internal error -- flip_one_bit() produced the same string as its input: %s == %s" % (result, s)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
@ -1,9 +1,26 @@
|
|||||||
|
|
||||||
import treq
|
import treq
|
||||||
from twisted.internet import defer
|
from twisted.internet.defer import (
|
||||||
|
maybeDeferred,
|
||||||
|
inlineCallbacks,
|
||||||
|
returnValue,
|
||||||
|
)
|
||||||
from twisted.web.error import Error
|
from twisted.web.error import Error
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
from nevow.context import WebContext
|
||||||
|
from nevow.testutil import FakeRequest
|
||||||
|
from nevow.appserver import (
|
||||||
|
processingFailed,
|
||||||
|
DefaultExceptionHandler,
|
||||||
|
)
|
||||||
|
from nevow.inevow import (
|
||||||
|
ICanHandleException,
|
||||||
|
IRequest,
|
||||||
|
IResource as INevowResource,
|
||||||
|
IData,
|
||||||
|
)
|
||||||
|
|
||||||
|
@inlineCallbacks
|
||||||
def do_http(method, url, **kwargs):
|
def do_http(method, url, **kwargs):
|
||||||
response = yield treq.request(method, url, persistent=False, **kwargs)
|
response = yield treq.request(method, url, persistent=False, **kwargs)
|
||||||
body = yield treq.content(response)
|
body = yield treq.content(response)
|
||||||
@ -11,4 +28,35 @@ def do_http(method, url, **kwargs):
|
|||||||
# https://github.com/twisted/treq/pull/159 has landed
|
# https://github.com/twisted/treq/pull/159 has landed
|
||||||
if 400 <= response.code < 600:
|
if 400 <= response.code < 600:
|
||||||
raise Error(response.code, response=body)
|
raise Error(response.code, response=body)
|
||||||
defer.returnValue(body)
|
returnValue(body)
|
||||||
|
|
||||||
|
|
||||||
|
def render(resource, query_args):
|
||||||
|
"""
|
||||||
|
Render (in the manner of the Nevow appserver) a Nevow ``Page`` or a
|
||||||
|
Twisted ``Resource`` against a request with the given query arguments .
|
||||||
|
|
||||||
|
:param resource: The page or resource to render.
|
||||||
|
|
||||||
|
:param query_args: The query arguments to put into the request being
|
||||||
|
rendered. A mapping from ``bytes`` to ``list`` of ``bytes``.
|
||||||
|
|
||||||
|
:return Deferred: A Deferred that fires with the rendered response body as
|
||||||
|
``bytes``.
|
||||||
|
"""
|
||||||
|
ctx = WebContext(tag=resource)
|
||||||
|
req = FakeRequest(args=query_args)
|
||||||
|
ctx.remember(DefaultExceptionHandler(), ICanHandleException)
|
||||||
|
ctx.remember(req, IRequest)
|
||||||
|
ctx.remember(None, IData)
|
||||||
|
|
||||||
|
def maybe_concat(res):
|
||||||
|
if isinstance(res, bytes):
|
||||||
|
return req.v + res
|
||||||
|
return req.v
|
||||||
|
|
||||||
|
resource = INevowResource(resource)
|
||||||
|
d = maybeDeferred(resource.renderHTTP, ctx)
|
||||||
|
d.addErrback(processingFailed, req, ctx)
|
||||||
|
d.addCallback(maybe_concat)
|
||||||
|
return d
|
||||||
|
@ -3,6 +3,8 @@ A storage server plugin the test suite can use to validate the
|
|||||||
functionality.
|
functionality.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from future.utils import native_str
|
||||||
|
|
||||||
from json import (
|
from json import (
|
||||||
dumps,
|
dumps,
|
||||||
)
|
)
|
||||||
@ -36,7 +38,7 @@ from allmydata.client import (
|
|||||||
|
|
||||||
|
|
||||||
class RIDummy(RemoteInterface):
|
class RIDummy(RemoteInterface):
|
||||||
__remote_name__ = "RIDummy.tahoe.allmydata.com"
|
__remote_name__ = native_str("RIDummy.tahoe.allmydata.com")
|
||||||
|
|
||||||
def just_some_method():
|
def just_some_method():
|
||||||
"""
|
"""
|
||||||
|
29
src/allmydata/test/test_common_util.py
Normal file
29
src/allmydata/test/test_common_util.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
"""
|
||||||
|
This module has been ported to Python 3.
|
||||||
|
"""
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import division
|
||||||
|
from __future__ import print_function
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from future.utils import PY2
|
||||||
|
if PY2:
|
||||||
|
from future.builtins import filter, map, zip, ascii, chr, hex, input, next, oct, open, pow, round, super, bytes, dict, list, object, range, str, max, min # noqa: F401
|
||||||
|
|
||||||
|
import random
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from allmydata.test.common_util import flip_one_bit
|
||||||
|
|
||||||
|
|
||||||
|
class TestFlipOneBit(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
random.seed(42) # I tried using version=1 on PY3 to avoid the if below, to no avail.
|
||||||
|
|
||||||
|
def test_accepts_byte_string(self):
|
||||||
|
actual = flip_one_bit(b'foo')
|
||||||
|
self.assertEqual(actual, b'fno' if PY2 else b'fom')
|
||||||
|
|
||||||
|
def test_rejects_unicode_string(self):
|
||||||
|
self.assertRaises(AssertionError, flip_one_bit, u'foo')
|
@ -1,4 +1,14 @@
|
|||||||
|
"""
|
||||||
|
Ported to Python 3.
|
||||||
|
"""
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import division
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from future.utils import PY2, bchr
|
||||||
|
if PY2:
|
||||||
|
from future.builtins import filter, map, zip, ascii, chr, hex, input, next, oct, open, pow, round, super, bytes, dict, list, object, range, str, max, min # noqa: F401
|
||||||
|
|
||||||
# system-level upload+download roundtrip test, but using shares created from
|
# system-level upload+download roundtrip test, but using shares created from
|
||||||
# a previous run. This asserts that the current code is capable of decoding
|
# a previous run. This asserts that the current code is capable of decoding
|
||||||
@ -27,58 +37,58 @@ from foolscap.eventual import eventually, fireEventually, flushEventualQueue
|
|||||||
if six.PY3:
|
if six.PY3:
|
||||||
long = int
|
long = int
|
||||||
|
|
||||||
plaintext = "This is a moderate-sized file.\n" * 10
|
plaintext = b"This is a moderate-sized file.\n" * 10
|
||||||
mutable_plaintext = "This is a moderate-sized mutable file.\n" * 10
|
mutable_plaintext = b"This is a moderate-sized mutable file.\n" * 10
|
||||||
|
|
||||||
# this chunk was generated by create_share(), written to disk, then pasted
|
# this chunk was generated by create_share(), written to disk, then pasted
|
||||||
# into this file. These shares were created by 1.2.0-r3247, a version that's
|
# into this file. These shares were created by 1.2.0-r3247, a version that's
|
||||||
# probably fairly close to 1.3.0 .
|
# probably fairly close to 1.3.0 .
|
||||||
#--------- BEGIN stored_shares.py --------------
|
#--------- BEGIN stored_shares.py --------------
|
||||||
immutable_uri = "URI:CHK:g4i6qkk7mlj4vkl5ncg6dwo73i:qcas2ebousfk3q5rkl2ncayeku52kpyse76v5yeel2t2eaa4f6ha:3:10:310"
|
immutable_uri = b"URI:CHK:g4i6qkk7mlj4vkl5ncg6dwo73i:qcas2ebousfk3q5rkl2ncayeku52kpyse76v5yeel2t2eaa4f6ha:3:10:310"
|
||||||
immutable_shares = {
|
immutable_shares = {
|
||||||
0: { # client[0]
|
0: { # client[0]
|
||||||
0: base32.a2b("aaaaaaiaaacyeaaaaaaqaaaaaeaaaadiaaaaa2aaaaaciaaaacgaaaaavqaaaagmaaaab3aaaaazmksehmgmlmmeqkbxbljh5qnfq36b7h5ukgqccmy3665khphcxihkce7jukeuegdxtn26p353ork6qihitbshwucpopzvdnpkflg6vbvko7ohcmxjywpdkvjmuzq6hysxfl74mamn224nrsyl7czmvtwtss6kkzljridkffeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactwxn7tsxj2nh6skwbghycguqfj7xrpegeporex5ebctynbgbl7y5y3kjcfritduzdk5rvwqs4lwzvb7fgvljgozbbtamhoriuzaeruaaqt2fbbxr5yv4vqeabkjqow6sd73dfqab3qban3htx6rn2y6mujdwaacbpvbyim4ewanv2vku44tunk7vdjkty2wkfm3jg67pqmm2newyib4aafazigyt6kxmirnlio5sdvbkvh43rwpctm6coigl64chn6z7w45rcaaccvmfgplu4kz5erphnx3xhzclypawi2j5zsvewmn4s2wbba4k2ktaab45y3kjcfritduzdk5rvwqs4lwzvb7fgvljgozbbtamhoriuzaeruaaaae4gg33emvrv63tbnvstumz2mnzhglddn5sgky27obqxeylnom5dqortgezc2mzngeycyy3spfyhi5dfpb2f62dbonudumzshkl7fjw5sp7x3yw4sdhze6qf7zgsjocpqtwl2gj5o6vufvixto3u2lddoj4xa5dumv4hix3sn5xxix3imfzwqortgi5fhno37hfotu2p5evmcmpqenjakt7pc6imi65cjp2icfhq2cmcx7rmnzswkzdfmrpxg2dbojsxgorrhizsy3tvnvpxgzlhnvsw45dthiytumjmonswo3lfnz2f643jpjstumz2gmyteldtnbqxezk7ojxw65c7nbqxg2b2gmzdubzmius26hljzu4j7gq5hdshwueqcfjc2bmveiyqbdxgyejetzovfrzws6tfhiztumzrgawhiyljnrpwg33emvrv64dbojqw24z2ha5dgmjsfuzs2mjqfr2g65dbnrpxg2dbojsxgorshiytalaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabj5uiln36za2n4oyier7k5e4sx6newmmflfqhj7xffy32p5iohlyf33bdx5dafkfwr7rxwxjcsg3ljflkaae537llwnnykgf36h52dojfplbwi"),
|
0: base32.a2b(b"aaaaaaiaaacyeaaaaaaqaaaaaeaaaadiaaaaa2aaaaaciaaaacgaaaaavqaaaagmaaaab3aaaaazmksehmgmlmmeqkbxbljh5qnfq36b7h5ukgqccmy3665khphcxihkce7jukeuegdxtn26p353ork6qihitbshwucpopzvdnpkflg6vbvko7ohcmxjywpdkvjmuzq6hysxfl74mamn224nrsyl7czmvtwtss6kkzljridkffeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactwxn7tsxj2nh6skwbghycguqfj7xrpegeporex5ebctynbgbl7y5y3kjcfritduzdk5rvwqs4lwzvb7fgvljgozbbtamhoriuzaeruaaqt2fbbxr5yv4vqeabkjqow6sd73dfqab3qban3htx6rn2y6mujdwaacbpvbyim4ewanv2vku44tunk7vdjkty2wkfm3jg67pqmm2newyib4aafazigyt6kxmirnlio5sdvbkvh43rwpctm6coigl64chn6z7w45rcaaccvmfgplu4kz5erphnx3xhzclypawi2j5zsvewmn4s2wbba4k2ktaab45y3kjcfritduzdk5rvwqs4lwzvb7fgvljgozbbtamhoriuzaeruaaaae4gg33emvrv63tbnvstumz2mnzhglddn5sgky27obqxeylnom5dqortgezc2mzngeycyy3spfyhi5dfpb2f62dbonudumzshkl7fjw5sp7x3yw4sdhze6qf7zgsjocpqtwl2gj5o6vufvixto3u2lddoj4xa5dumv4hix3sn5xxix3imfzwqortgi5fhno37hfotu2p5evmcmpqenjakt7pc6imi65cjp2icfhq2cmcx7rmnzswkzdfmrpxg2dbojsxgorrhizsy3tvnvpxgzlhnvsw45dthiytumjmonswo3lfnz2f643jpjstumz2gmyteldtnbqxezk7ojxw65c7nbqxg2b2gmzdubzmius26hljzu4j7gq5hdshwueqcfjc2bmveiyqbdxgyejetzovfrzws6tfhiztumzrgawhiyljnrpwg33emvrv64dbojqw24z2ha5dgmjsfuzs2mjqfr2g65dbnrpxg2dbojsxgorshiytalaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabj5uiln36za2n4oyier7k5e4sx6newmmflfqhj7xffy32p5iohlyf33bdx5dafkfwr7rxwxjcsg3ljflkaae537llwnnykgf36h52dojfplbwi"),
|
||||||
5: base32.a2b("aaaaaaiaaacyeaaaaaaqaaaaaeaaaadiaaaaa2aaaaaciaaaacgaaaaavqaaaagmaaaab3aaaaazmsdsvwbnfx2rnh7dusqniqomsdeetuafps6cawyb4pzxpkzal7w5ufaknxfnqw2qywv4c3a2zlumb2x2rx5osbxd3kqmebjndqf7zihbtagqczgwrka5rnywtsaeyijyh26okua2u7loep2nzo5etirjrxmp3yxpb4pheusaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactwxn7tsxj2nh6skwbghycguqfj7xrpegeporex5ebctynbgbl7zs3zcg7igd2xoa4eu3lffqginpmoxrshqe6n3hzpocihgeu4vvymaadjz54nelgyi47767pkbsjwdjgsv7uyd5ntrztw6juavj7sd7wx7aaacx7wxlycyjniwxvby4ar546ncb4d3jnbhssnq4n4l4xeajurmn5diabgxwi6i5d2ysny3vavrm3a5lsuvng5mhbzk7axesyeddzw6uzmnluaakglpei35aypk5ydqstnmuwazbv5r26gi6atzxm7f5yja4ystswxbqaakbsqnrh4voyrc2wq53ehkcvkpzxdm6fgz4e4qmx5yeo35t7nz3ceaaaae4gg33emvrv63tbnvstumz2mnzhglddn5sgky27obqxeylnom5dqortgezc2mzngeycyy3spfyhi5dfpb2f62dbonudumzshkl7fjw5sp7x3yw4sdhze6qf7zgsjocpqtwl2gj5o6vufvixto3u2lddoj4xa5dumv4hix3sn5xxix3imfzwqortgi5fhno37hfotu2p5evmcmpqenjakt7pc6imi65cjp2icfhq2cmcx7rmnzswkzdfmrpxg2dbojsxgorrhizsy3tvnvpxgzlhnvsw45dthiytumjmonswo3lfnz2f643jpjstumz2gmyteldtnbqxezk7ojxw65c7nbqxg2b2gmzdubzmius26hljzu4j7gq5hdshwueqcfjc2bmveiyqbdxgyejetzovfrzws6tfhiztumzrgawhiyljnrpwg33emvrv64dbojqw24z2ha5dgmjsfuzs2mjqfr2g65dbnrpxg2dbojsxgorshiytalaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabj5uiln36za2n4oyier7k5e4sx6newmmflfqhj7xffy32p5iohlyf33bdx5dafkfwr7rxwxjcsg3ljflkaae537llwnnykgf36h52dojfplbwi"),
|
5: base32.a2b(b"aaaaaaiaaacyeaaaaaaqaaaaaeaaaadiaaaaa2aaaaaciaaaacgaaaaavqaaaagmaaaab3aaaaazmsdsvwbnfx2rnh7dusqniqomsdeetuafps6cawyb4pzxpkzal7w5ufaknxfnqw2qywv4c3a2zlumb2x2rx5osbxd3kqmebjndqf7zihbtagqczgwrka5rnywtsaeyijyh26okua2u7loep2nzo5etirjrxmp3yxpb4pheusaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactwxn7tsxj2nh6skwbghycguqfj7xrpegeporex5ebctynbgbl7zs3zcg7igd2xoa4eu3lffqginpmoxrshqe6n3hzpocihgeu4vvymaadjz54nelgyi47767pkbsjwdjgsv7uyd5ntrztw6juavj7sd7wx7aaacx7wxlycyjniwxvby4ar546ncb4d3jnbhssnq4n4l4xeajurmn5diabgxwi6i5d2ysny3vavrm3a5lsuvng5mhbzk7axesyeddzw6uzmnluaakglpei35aypk5ydqstnmuwazbv5r26gi6atzxm7f5yja4ystswxbqaakbsqnrh4voyrc2wq53ehkcvkpzxdm6fgz4e4qmx5yeo35t7nz3ceaaaae4gg33emvrv63tbnvstumz2mnzhglddn5sgky27obqxeylnom5dqortgezc2mzngeycyy3spfyhi5dfpb2f62dbonudumzshkl7fjw5sp7x3yw4sdhze6qf7zgsjocpqtwl2gj5o6vufvixto3u2lddoj4xa5dumv4hix3sn5xxix3imfzwqortgi5fhno37hfotu2p5evmcmpqenjakt7pc6imi65cjp2icfhq2cmcx7rmnzswkzdfmrpxg2dbojsxgorrhizsy3tvnvpxgzlhnvsw45dthiytumjmonswo3lfnz2f643jpjstumz2gmyteldtnbqxezk7ojxw65c7nbqxg2b2gmzdubzmius26hljzu4j7gq5hdshwueqcfjc2bmveiyqbdxgyejetzovfrzws6tfhiztumzrgawhiyljnrpwg33emvrv64dbojqw24z2ha5dgmjsfuzs2mjqfr2g65dbnrpxg2dbojsxgorshiytalaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabj5uiln36za2n4oyier7k5e4sx6newmmflfqhj7xffy32p5iohlyf33bdx5dafkfwr7rxwxjcsg3ljflkaae537llwnnykgf36h52dojfplbwi"),
|
||||||
},
|
},
|
||||||
1: { # client[1]
|
1: { # client[1]
|
||||||
2: base32.a2b("aaaaaaiaaacyeaaaaaaqaaaaaeaaaadiaaaaa2aaaaaciaaaacgaaaaavqaaaagmaaaab3aaaaazmj7um4zfgqo35m62ln6has6xz43klzjphj5eg46mb5x2jzgr6x6zb4voveo5uef53xbjbktr5rlupomy7x5b34amqeeg4r6obt6kpo2x4s3m3cwoo54oijyqfms3n3fethykhtglc47r4ci7ugqgz5d5fap3xzyhm4ehaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactwxn7tsxj2nh6skwbghycguqfj7xrpegeporex5ebctynbgbl7zqkzg32wa74epeppqwneujs6tjptlm4qw75hoafobsoif3ok5odkaarmcwjw6vqh7bdzd34ftjfcmxu2l423hefx7j3qblqmtsbo3sxlq2qaewyffwgzojfi4uj2praj5azehnr4fhan5kdyewhtfncrqzoe42ijeaaikvquz5otrlhusf45w7o47ejpb4czdjhxgkuszrxslkyeedrljkmaabigkbwe7sv3celk2dxmq5ikvj7g4ntyu3hqtsbs7xar3pwp5xhmiqaa6k7uub7uqlamlqi2oduautemch242scu7cfor6kedxs6mm3uwjsmaaaae4gg33emvrv63tbnvstumz2mnzhglddn5sgky27obqxeylnom5dqortgezc2mzngeycyy3spfyhi5dfpb2f62dbonudumzshkl7fjw5sp7x3yw4sdhze6qf7zgsjocpqtwl2gj5o6vufvixto3u2lddoj4xa5dumv4hix3sn5xxix3imfzwqortgi5fhno37hfotu2p5evmcmpqenjakt7pc6imi65cjp2icfhq2cmcx7rmnzswkzdfmrpxg2dbojsxgorrhizsy3tvnvpxgzlhnvsw45dthiytumjmonswo3lfnz2f643jpjstumz2gmyteldtnbqxezk7ojxw65c7nbqxg2b2gmzdubzmius26hljzu4j7gq5hdshwueqcfjc2bmveiyqbdxgyejetzovfrzws6tfhiztumzrgawhiyljnrpwg33emvrv64dbojqw24z2ha5dgmjsfuzs2mjqfr2g65dbnrpxg2dbojsxgorshiytalaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabdp37hh2k4ys4d7qusb5e3dakjntythtcwcwfok7e52pu64zn4wrwbtlkzxzntwuwemi6e6mek5n4i7h3bw7nkat2zmqieftinxgzl2jfplbwi"),
|
2: base32.a2b(b"aaaaaaiaaacyeaaaaaaqaaaaaeaaaadiaaaaa2aaaaaciaaaacgaaaaavqaaaagmaaaab3aaaaazmj7um4zfgqo35m62ln6has6xz43klzjphj5eg46mb5x2jzgr6x6zb4voveo5uef53xbjbktr5rlupomy7x5b34amqeeg4r6obt6kpo2x4s3m3cwoo54oijyqfms3n3fethykhtglc47r4ci7ugqgz5d5fap3xzyhm4ehaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactwxn7tsxj2nh6skwbghycguqfj7xrpegeporex5ebctynbgbl7zqkzg32wa74epeppqwneujs6tjptlm4qw75hoafobsoif3ok5odkaarmcwjw6vqh7bdzd34ftjfcmxu2l423hefx7j3qblqmtsbo3sxlq2qaewyffwgzojfi4uj2praj5azehnr4fhan5kdyewhtfncrqzoe42ijeaaikvquz5otrlhusf45w7o47ejpb4czdjhxgkuszrxslkyeedrljkmaabigkbwe7sv3celk2dxmq5ikvj7g4ntyu3hqtsbs7xar3pwp5xhmiqaa6k7uub7uqlamlqi2oduautemch242scu7cfor6kedxs6mm3uwjsmaaaae4gg33emvrv63tbnvstumz2mnzhglddn5sgky27obqxeylnom5dqortgezc2mzngeycyy3spfyhi5dfpb2f62dbonudumzshkl7fjw5sp7x3yw4sdhze6qf7zgsjocpqtwl2gj5o6vufvixto3u2lddoj4xa5dumv4hix3sn5xxix3imfzwqortgi5fhno37hfotu2p5evmcmpqenjakt7pc6imi65cjp2icfhq2cmcx7rmnzswkzdfmrpxg2dbojsxgorrhizsy3tvnvpxgzlhnvsw45dthiytumjmonswo3lfnz2f643jpjstumz2gmyteldtnbqxezk7ojxw65c7nbqxg2b2gmzdubzmius26hljzu4j7gq5hdshwueqcfjc2bmveiyqbdxgyejetzovfrzws6tfhiztumzrgawhiyljnrpwg33emvrv64dbojqw24z2ha5dgmjsfuzs2mjqfr2g65dbnrpxg2dbojsxgorshiytalaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabdp37hh2k4ys4d7qusb5e3dakjntythtcwcwfok7e52pu64zn4wrwbtlkzxzntwuwemi6e6mek5n4i7h3bw7nkat2zmqieftinxgzl2jfplbwi"),
|
||||||
7: base32.a2b("aaaaaaiaaacyeaaaaaaqaaaaaeaaaadiaaaaa2aaaaaciaaaacgaaaaavqaaaagmaaaab3aaaaaznhsh2frhzxbutelvddtbuf3tfilhcj2zi3cxjyzy7pg7ewamazcblv76mvey54fxmch64chqfi24jmondc4uzitby3wjeui4nfp7kv6ufo67exptkvwk7cnbouvjiapyqzrps4r6ise4jhlr7mtp2tlizb5hyaqm3fhsvrmqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactwxn7tsxj2nh6skwbghycguqfj7xrpegeporex5ebctynbgbl72g6h2oewtfcwgupjbjnh4k5k6d3k2fpi2q6nyidh3yo5ui6cslreaajms7f3pcsywhjbgrybzp64jzlsyjqbu7h4hvdlwf77ar6l63imdeqaaudfa3cpzk5rcfvnb3wioufku7togz4kntyjzazp3qi5x3h63tweiaagtt3y2iwnqrz77566udetmgsnfl7jqh23hdthn4tibkt7eh7np6aaakvpbzjdki64qaigkdj2bven3uigxbpurpwtrkjs4b6habv2ls7zqaac2g6h2oewtfcwgupjbjnh4k5k6d3k2fpi2q6nyidh3yo5ui6cslreaaaae4gg33emvrv63tbnvstumz2mnzhglddn5sgky27obqxeylnom5dqortgezc2mzngeycyy3spfyhi5dfpb2f62dbonudumzshkl7fjw5sp7x3yw4sdhze6qf7zgsjocpqtwl2gj5o6vufvixto3u2lddoj4xa5dumv4hix3sn5xxix3imfzwqortgi5fhno37hfotu2p5evmcmpqenjakt7pc6imi65cjp2icfhq2cmcx7rmnzswkzdfmrpxg2dbojsxgorrhizsy3tvnvpxgzlhnvsw45dthiytumjmonswo3lfnz2f643jpjstumz2gmyteldtnbqxezk7ojxw65c7nbqxg2b2gmzdubzmius26hljzu4j7gq5hdshwueqcfjc2bmveiyqbdxgyejetzovfrzws6tfhiztumzrgawhiyljnrpwg33emvrv64dbojqw24z2ha5dgmjsfuzs2mjqfr2g65dbnrpxg2dbojsxgorshiytalaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabdp37hh2k4ys4d7qusb5e3dakjntythtcwcwfok7e52pu64zn4wrwbtlkzxzntwuwemi6e6mek5n4i7h3bw7nkat2zmqieftinxgzl2jfplbwi"),
|
7: base32.a2b(b"aaaaaaiaaacyeaaaaaaqaaaaaeaaaadiaaaaa2aaaaaciaaaacgaaaaavqaaaagmaaaab3aaaaaznhsh2frhzxbutelvddtbuf3tfilhcj2zi3cxjyzy7pg7ewamazcblv76mvey54fxmch64chqfi24jmondc4uzitby3wjeui4nfp7kv6ufo67exptkvwk7cnbouvjiapyqzrps4r6ise4jhlr7mtp2tlizb5hyaqm3fhsvrmqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactwxn7tsxj2nh6skwbghycguqfj7xrpegeporex5ebctynbgbl72g6h2oewtfcwgupjbjnh4k5k6d3k2fpi2q6nyidh3yo5ui6cslreaajms7f3pcsywhjbgrybzp64jzlsyjqbu7h4hvdlwf77ar6l63imdeqaaudfa3cpzk5rcfvnb3wioufku7togz4kntyjzazp3qi5x3h63tweiaagtt3y2iwnqrz77566udetmgsnfl7jqh23hdthn4tibkt7eh7np6aaakvpbzjdki64qaigkdj2bven3uigxbpurpwtrkjs4b6habv2ls7zqaac2g6h2oewtfcwgupjbjnh4k5k6d3k2fpi2q6nyidh3yo5ui6cslreaaaae4gg33emvrv63tbnvstumz2mnzhglddn5sgky27obqxeylnom5dqortgezc2mzngeycyy3spfyhi5dfpb2f62dbonudumzshkl7fjw5sp7x3yw4sdhze6qf7zgsjocpqtwl2gj5o6vufvixto3u2lddoj4xa5dumv4hix3sn5xxix3imfzwqortgi5fhno37hfotu2p5evmcmpqenjakt7pc6imi65cjp2icfhq2cmcx7rmnzswkzdfmrpxg2dbojsxgorrhizsy3tvnvpxgzlhnvsw45dthiytumjmonswo3lfnz2f643jpjstumz2gmyteldtnbqxezk7ojxw65c7nbqxg2b2gmzdubzmius26hljzu4j7gq5hdshwueqcfjc2bmveiyqbdxgyejetzovfrzws6tfhiztumzrgawhiyljnrpwg33emvrv64dbojqw24z2ha5dgmjsfuzs2mjqfr2g65dbnrpxg2dbojsxgorshiytalaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabdp37hh2k4ys4d7qusb5e3dakjntythtcwcwfok7e52pu64zn4wrwbtlkzxzntwuwemi6e6mek5n4i7h3bw7nkat2zmqieftinxgzl2jfplbwi"),
|
||||||
},
|
},
|
||||||
2: { # client[2]
|
2: { # client[2]
|
||||||
1: base32.a2b("aaaaaaiaaacyeaaaaaaqaaaaaeaaaadiaaaaa2aaaaaciaaaacgaaaaavqaaaagmaaaab3aaaaazmkrwrt6figauxkgqyk3nggp5eeoeq5htt7tke4gfqj2u5roieslao4fldcwlq4btzk4brhkaerqiih6mhudotttrb6xzmvnqgg33fjcqeuw6teb3gml2pmhsezisa5svnzlvqnbaz6kzdmhisbwgu6ocexf2ge2rvc67gneqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactwxn7tsxj2nh6skwbghycguqfj7xrpegeporex5ebctynbgbl72piueg6hxcxswaqafjgb232ip7mmwaahoaebxm6o72fxldzsreoyaaif6uhbbtqsybwxkvkttsorvl6unfkpdkzivtne3356brtjus3bahqaee6riin4pofpfmbaaksmdvxuq76yzmaao4aidoz457ulowhtfci5qaafazigyt6kxmirnlio5sdvbkvh43rwpctm6coigl64chn6z7w45rcaaccvmfgplu4kz5erphnx3xhzclypawi2j5zsvewmn4s2wbba4k2ktaab45y3kjcfritduzdk5rvwqs4lwzvb7fgvljgozbbtamhoriuzaeruaaaae4gg33emvrv63tbnvstumz2mnzhglddn5sgky27obqxeylnom5dqortgezc2mzngeycyy3spfyhi5dfpb2f62dbonudumzshkl7fjw5sp7x3yw4sdhze6qf7zgsjocpqtwl2gj5o6vufvixto3u2lddoj4xa5dumv4hix3sn5xxix3imfzwqortgi5fhno37hfotu2p5evmcmpqenjakt7pc6imi65cjp2icfhq2cmcx7rmnzswkzdfmrpxg2dbojsxgorrhizsy3tvnvpxgzlhnvsw45dthiytumjmonswo3lfnz2f643jpjstumz2gmyteldtnbqxezk7ojxw65c7nbqxg2b2gmzdubzmius26hljzu4j7gq5hdshwueqcfjc2bmveiyqbdxgyejetzovfrzws6tfhiztumzrgawhiyljnrpwg33emvrv64dbojqw24z2ha5dgmjsfuzs2mjqfr2g65dbnrpxg2dbojsxgorshiytalaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaugotrr7enihxy2b2nwodhxabihaf3ewc2hmcdjsqx5hi4h3rn7gnvpt3lzzo5qgbnlp4dybwr7dn7vu5hsiyo5pedlqcasb7csiuojfplbwi"),
|
1: base32.a2b(b"aaaaaaiaaacyeaaaaaaqaaaaaeaaaadiaaaaa2aaaaaciaaaacgaaaaavqaaaagmaaaab3aaaaazmkrwrt6figauxkgqyk3nggp5eeoeq5htt7tke4gfqj2u5roieslao4fldcwlq4btzk4brhkaerqiih6mhudotttrb6xzmvnqgg33fjcqeuw6teb3gml2pmhsezisa5svnzlvqnbaz6kzdmhisbwgu6ocexf2ge2rvc67gneqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactwxn7tsxj2nh6skwbghycguqfj7xrpegeporex5ebctynbgbl72piueg6hxcxswaqafjgb232ip7mmwaahoaebxm6o72fxldzsreoyaaif6uhbbtqsybwxkvkttsorvl6unfkpdkzivtne3356brtjus3bahqaee6riin4pofpfmbaaksmdvxuq76yzmaao4aidoz457ulowhtfci5qaafazigyt6kxmirnlio5sdvbkvh43rwpctm6coigl64chn6z7w45rcaaccvmfgplu4kz5erphnx3xhzclypawi2j5zsvewmn4s2wbba4k2ktaab45y3kjcfritduzdk5rvwqs4lwzvb7fgvljgozbbtamhoriuzaeruaaaae4gg33emvrv63tbnvstumz2mnzhglddn5sgky27obqxeylnom5dqortgezc2mzngeycyy3spfyhi5dfpb2f62dbonudumzshkl7fjw5sp7x3yw4sdhze6qf7zgsjocpqtwl2gj5o6vufvixto3u2lddoj4xa5dumv4hix3sn5xxix3imfzwqortgi5fhno37hfotu2p5evmcmpqenjakt7pc6imi65cjp2icfhq2cmcx7rmnzswkzdfmrpxg2dbojsxgorrhizsy3tvnvpxgzlhnvsw45dthiytumjmonswo3lfnz2f643jpjstumz2gmyteldtnbqxezk7ojxw65c7nbqxg2b2gmzdubzmius26hljzu4j7gq5hdshwueqcfjc2bmveiyqbdxgyejetzovfrzws6tfhiztumzrgawhiyljnrpwg33emvrv64dbojqw24z2ha5dgmjsfuzs2mjqfr2g65dbnrpxg2dbojsxgorshiytalaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaugotrr7enihxy2b2nwodhxabihaf3ewc2hmcdjsqx5hi4h3rn7gnvpt3lzzo5qgbnlp4dybwr7dn7vu5hsiyo5pedlqcasb7csiuojfplbwi"),
|
||||||
6: base32.a2b("aaaaaaiaaacyeaaaaaaqaaaaaeaaaadiaaaaa2aaaaaciaaaacgaaaaavqaaaagmaaaab3aaaaazm34cgyp37ou5ohrofmk6bf5gcppxeb2njwmiwasn3uh4ykeocvq4vydsw36ksh63fcil3o257zupffrruiuqlwjvbdcdjiuqrojiromunzxxc34io7zlfafprzlvmztph4qsp67ozxmwvivqwtvu6ckr7pffsikgi2supviqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactwxn7tsxj2nh6skwbghycguqfj7xrpegeporex5ebctynbgbl7zlyoki2shxeacbsq2oqnjdo5cbvyl5el5u4ksmxapryanos4x6maaajms7f3pcsywhjbgrybzp64jzlsyjqbu7h4hvdlwf77ar6l63imdeqaaudfa3cpzk5rcfvnb3wioufku7togz4kntyjzazp3qi5x3h63tweiaagtt3y2iwnqrz77566udetmgsnfl7jqh23hdthn4tibkt7eh7np6aaakvpbzjdki64qaigkdj2bven3uigxbpurpwtrkjs4b6habv2ls7zqaac2g6h2oewtfcwgupjbjnh4k5k6d3k2fpi2q6nyidh3yo5ui6cslreaaaae4gg33emvrv63tbnvstumz2mnzhglddn5sgky27obqxeylnom5dqortgezc2mzngeycyy3spfyhi5dfpb2f62dbonudumzshkl7fjw5sp7x3yw4sdhze6qf7zgsjocpqtwl2gj5o6vufvixto3u2lddoj4xa5dumv4hix3sn5xxix3imfzwqortgi5fhno37hfotu2p5evmcmpqenjakt7pc6imi65cjp2icfhq2cmcx7rmnzswkzdfmrpxg2dbojsxgorrhizsy3tvnvpxgzlhnvsw45dthiytumjmonswo3lfnz2f643jpjstumz2gmyteldtnbqxezk7ojxw65c7nbqxg2b2gmzdubzmius26hljzu4j7gq5hdshwueqcfjc2bmveiyqbdxgyejetzovfrzws6tfhiztumzrgawhiyljnrpwg33emvrv64dbojqw24z2ha5dgmjsfuzs2mjqfr2g65dbnrpxg2dbojsxgorshiytalaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaugotrr7enihxy2b2nwodhxabihaf3ewc2hmcdjsqx5hi4h3rn7gnvpt3lzzo5qgbnlp4dybwr7dn7vu5hsiyo5pedlqcasb7csiuojfplbwi"),
|
6: base32.a2b(b"aaaaaaiaaacyeaaaaaaqaaaaaeaaaadiaaaaa2aaaaaciaaaacgaaaaavqaaaagmaaaab3aaaaazm34cgyp37ou5ohrofmk6bf5gcppxeb2njwmiwasn3uh4ykeocvq4vydsw36ksh63fcil3o257zupffrruiuqlwjvbdcdjiuqrojiromunzxxc34io7zlfafprzlvmztph4qsp67ozxmwvivqwtvu6ckr7pffsikgi2supviqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactwxn7tsxj2nh6skwbghycguqfj7xrpegeporex5ebctynbgbl7zlyoki2shxeacbsq2oqnjdo5cbvyl5el5u4ksmxapryanos4x6maaajms7f3pcsywhjbgrybzp64jzlsyjqbu7h4hvdlwf77ar6l63imdeqaaudfa3cpzk5rcfvnb3wioufku7togz4kntyjzazp3qi5x3h63tweiaagtt3y2iwnqrz77566udetmgsnfl7jqh23hdthn4tibkt7eh7np6aaakvpbzjdki64qaigkdj2bven3uigxbpurpwtrkjs4b6habv2ls7zqaac2g6h2oewtfcwgupjbjnh4k5k6d3k2fpi2q6nyidh3yo5ui6cslreaaaae4gg33emvrv63tbnvstumz2mnzhglddn5sgky27obqxeylnom5dqortgezc2mzngeycyy3spfyhi5dfpb2f62dbonudumzshkl7fjw5sp7x3yw4sdhze6qf7zgsjocpqtwl2gj5o6vufvixto3u2lddoj4xa5dumv4hix3sn5xxix3imfzwqortgi5fhno37hfotu2p5evmcmpqenjakt7pc6imi65cjp2icfhq2cmcx7rmnzswkzdfmrpxg2dbojsxgorrhizsy3tvnvpxgzlhnvsw45dthiytumjmonswo3lfnz2f643jpjstumz2gmyteldtnbqxezk7ojxw65c7nbqxg2b2gmzdubzmius26hljzu4j7gq5hdshwueqcfjc2bmveiyqbdxgyejetzovfrzws6tfhiztumzrgawhiyljnrpwg33emvrv64dbojqw24z2ha5dgmjsfuzs2mjqfr2g65dbnrpxg2dbojsxgorshiytalaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaugotrr7enihxy2b2nwodhxabihaf3ewc2hmcdjsqx5hi4h3rn7gnvpt3lzzo5qgbnlp4dybwr7dn7vu5hsiyo5pedlqcasb7csiuojfplbwi"),
|
||||||
},
|
},
|
||||||
3: { # client[3]
|
3: { # client[3]
|
||||||
4: base32.a2b("aaaaaaiaaacyeaaaaaaqaaaaaeaaaadiaaaaa2aaaaaciaaaacgaaaaavqaaaagmaaaab3aaaaaznjqn7ehmj6f4p3fjyliuvwnfothumsfhs7ienw4uln6joaxopqlmcy5daa4njrkgj7nqm6tpnmz2dci2b356pljv4zjj5ayzfihi4g26qdei7kjtegjuv4d3k3t4orpufnft3edbondkpj5etjczwhyulukzuy5socyivdfqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactwxn7tsxj2nh6skwbghycguqfj7xrpegeporex5ebctynbgbl7zpmr4r2hvre3rxkblczwb2xfjk2n2yodsv6bojfqightn5jsy2xiaatl3epeor5mjg4n2qkywnqovzkkwtowdq4vpqlsjmcbr43pkmwgv2aacx7wxlycyjniwxvby4ar546ncb4d3jnbhssnq4n4l4xeajurmn5diaagtt3y2iwnqrz77566udetmgsnfl7jqh23hdthn4tibkt7eh7np6aaakglpei35aypk5ydqstnmuwazbv5r26gi6atzxm7f5yja4ystswxbqaakbsqnrh4voyrc2wq53ehkcvkpzxdm6fgz4e4qmx5yeo35t7nz3ceaaaae4gg33emvrv63tbnvstumz2mnzhglddn5sgky27obqxeylnom5dqortgezc2mzngeycyy3spfyhi5dfpb2f62dbonudumzshkl7fjw5sp7x3yw4sdhze6qf7zgsjocpqtwl2gj5o6vufvixto3u2lddoj4xa5dumv4hix3sn5xxix3imfzwqortgi5fhno37hfotu2p5evmcmpqenjakt7pc6imi65cjp2icfhq2cmcx7rmnzswkzdfmrpxg2dbojsxgorrhizsy3tvnvpxgzlhnvsw45dthiytumjmonswo3lfnz2f643jpjstumz2gmyteldtnbqxezk7ojxw65c7nbqxg2b2gmzdubzmius26hljzu4j7gq5hdshwueqcfjc2bmveiyqbdxgyejetzovfrzws6tfhiztumzrgawhiyljnrpwg33emvrv64dbojqw24z2ha5dgmjsfuzs2mjqfr2g65dbnrpxg2dbojsxgorshiytalaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacifoqlus3puiqkekp6g6fdecjcx2bak27angodamzoxugovlhtcj5xbly7teqwmf73fqk3clyfvs6hdauq5qnqahlxlmp2vrmnneedgjfplbwi"),
|
4: base32.a2b(b"aaaaaaiaaacyeaaaaaaqaaaaaeaaaadiaaaaa2aaaaaciaaaacgaaaaavqaaaagmaaaab3aaaaaznjqn7ehmj6f4p3fjyliuvwnfothumsfhs7ienw4uln6joaxopqlmcy5daa4njrkgj7nqm6tpnmz2dci2b356pljv4zjj5ayzfihi4g26qdei7kjtegjuv4d3k3t4orpufnft3edbondkpj5etjczwhyulukzuy5socyivdfqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactwxn7tsxj2nh6skwbghycguqfj7xrpegeporex5ebctynbgbl7zpmr4r2hvre3rxkblczwb2xfjk2n2yodsv6bojfqightn5jsy2xiaatl3epeor5mjg4n2qkywnqovzkkwtowdq4vpqlsjmcbr43pkmwgv2aacx7wxlycyjniwxvby4ar546ncb4d3jnbhssnq4n4l4xeajurmn5diaagtt3y2iwnqrz77566udetmgsnfl7jqh23hdthn4tibkt7eh7np6aaakglpei35aypk5ydqstnmuwazbv5r26gi6atzxm7f5yja4ystswxbqaakbsqnrh4voyrc2wq53ehkcvkpzxdm6fgz4e4qmx5yeo35t7nz3ceaaaae4gg33emvrv63tbnvstumz2mnzhglddn5sgky27obqxeylnom5dqortgezc2mzngeycyy3spfyhi5dfpb2f62dbonudumzshkl7fjw5sp7x3yw4sdhze6qf7zgsjocpqtwl2gj5o6vufvixto3u2lddoj4xa5dumv4hix3sn5xxix3imfzwqortgi5fhno37hfotu2p5evmcmpqenjakt7pc6imi65cjp2icfhq2cmcx7rmnzswkzdfmrpxg2dbojsxgorrhizsy3tvnvpxgzlhnvsw45dthiytumjmonswo3lfnz2f643jpjstumz2gmyteldtnbqxezk7ojxw65c7nbqxg2b2gmzdubzmius26hljzu4j7gq5hdshwueqcfjc2bmveiyqbdxgyejetzovfrzws6tfhiztumzrgawhiyljnrpwg33emvrv64dbojqw24z2ha5dgmjsfuzs2mjqfr2g65dbnrpxg2dbojsxgorshiytalaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacifoqlus3puiqkekp6g6fdecjcx2bak27angodamzoxugovlhtcj5xbly7teqwmf73fqk3clyfvs6hdauq5qnqahlxlmp2vrmnneedgjfplbwi"),
|
||||||
9: base32.a2b("aaaaaaiaaacyeaaaaaaqaaaaaeaaaadiaaaaa2aaaaaciaaaacgaaaaavqaaaagmaaaab3aaaaazn2tz3qt62bgsdnvksvdegsylb2kbltouheryflpho7hugme7svk7so2v7hmcgc43tcyugybuqzgifvkllikfiiezvml7ilolb7ivwvrv4d4t2gbywa44ibqwogmjtffta4b2sfwqebfg7pptergeqm5wo3tndtf7p3vftabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactwxn7tsxj2nh6skwbghycguqfj7xrpegeporex5ebctynbgbl7y3m26swfhsb66ze4cmyhohaksid7fyljgkhag32ibc7vx2yj4j5saayg3gxuvrj4qpxwjhatgb3rycusa7zoc2jsrybw6saix5n6wcpcpmqaamxjsc6bwv4w4or2oylltmsbfbobvmenj3sa6lnq6iy4tugsnv72eaaybvqu3gmlomi3dnf2tum3hoseavpesyia2i2wqgwbmbtrgmotu6oaadirzs2idl54toffh4a2hehvg2e3zoed4dr6pcdpuqpnz2knte7gqqac6kfatp33ianoqvg6mdd4vaxa27lo6vpugbcvanhskaqq2kewn6kwaaaae4gg33emvrv63tbnvstumz2mnzhglddn5sgky27obqxeylnom5dqortgezc2mzngeycyy3spfyhi5dfpb2f62dbonudumzshkl7fjw5sp7x3yw4sdhze6qf7zgsjocpqtwl2gj5o6vufvixto3u2lddoj4xa5dumv4hix3sn5xxix3imfzwqortgi5fhno37hfotu2p5evmcmpqenjakt7pc6imi65cjp2icfhq2cmcx7rmnzswkzdfmrpxg2dbojsxgorrhizsy3tvnvpxgzlhnvsw45dthiytumjmonswo3lfnz2f643jpjstumz2gmyteldtnbqxezk7ojxw65c7nbqxg2b2gmzdubzmius26hljzu4j7gq5hdshwueqcfjc2bmveiyqbdxgyejetzovfrzws6tfhiztumzrgawhiyljnrpwg33emvrv64dbojqw24z2ha5dgmjsfuzs2mjqfr2g65dbnrpxg2dbojsxgorshiytalaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacifoqlus3puiqkekp6g6fdecjcx2bak27angodamzoxugovlhtcj5xbly7teqwmf73fqk3clyfvs6hdauq5qnqahlxlmp2vrmnneedgjfplbwi"),
|
9: base32.a2b(b"aaaaaaiaaacyeaaaaaaqaaaaaeaaaadiaaaaa2aaaaaciaaaacgaaaaavqaaaagmaaaab3aaaaazn2tz3qt62bgsdnvksvdegsylb2kbltouheryflpho7hugme7svk7so2v7hmcgc43tcyugybuqzgifvkllikfiiezvml7ilolb7ivwvrv4d4t2gbywa44ibqwogmjtffta4b2sfwqebfg7pptergeqm5wo3tndtf7p3vftabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactwxn7tsxj2nh6skwbghycguqfj7xrpegeporex5ebctynbgbl7y3m26swfhsb66ze4cmyhohaksid7fyljgkhag32ibc7vx2yj4j5saayg3gxuvrj4qpxwjhatgb3rycusa7zoc2jsrybw6saix5n6wcpcpmqaamxjsc6bwv4w4or2oylltmsbfbobvmenj3sa6lnq6iy4tugsnv72eaaybvqu3gmlomi3dnf2tum3hoseavpesyia2i2wqgwbmbtrgmotu6oaadirzs2idl54toffh4a2hehvg2e3zoed4dr6pcdpuqpnz2knte7gqqac6kfatp33ianoqvg6mdd4vaxa27lo6vpugbcvanhskaqq2kewn6kwaaaae4gg33emvrv63tbnvstumz2mnzhglddn5sgky27obqxeylnom5dqortgezc2mzngeycyy3spfyhi5dfpb2f62dbonudumzshkl7fjw5sp7x3yw4sdhze6qf7zgsjocpqtwl2gj5o6vufvixto3u2lddoj4xa5dumv4hix3sn5xxix3imfzwqortgi5fhno37hfotu2p5evmcmpqenjakt7pc6imi65cjp2icfhq2cmcx7rmnzswkzdfmrpxg2dbojsxgorrhizsy3tvnvpxgzlhnvsw45dthiytumjmonswo3lfnz2f643jpjstumz2gmyteldtnbqxezk7ojxw65c7nbqxg2b2gmzdubzmius26hljzu4j7gq5hdshwueqcfjc2bmveiyqbdxgyejetzovfrzws6tfhiztumzrgawhiyljnrpwg33emvrv64dbojqw24z2ha5dgmjsfuzs2mjqfr2g65dbnrpxg2dbojsxgorshiytalaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacifoqlus3puiqkekp6g6fdecjcx2bak27angodamzoxugovlhtcj5xbly7teqwmf73fqk3clyfvs6hdauq5qnqahlxlmp2vrmnneedgjfplbwi"),
|
||||||
},
|
},
|
||||||
4: { # client[4]
|
4: { # client[4]
|
||||||
3: base32.a2b("aaaaaaiaaacyeaaaaaaqaaaaaeaaaadiaaaaa2aaaaaciaaaacgaaaaavqaaaagmaaaab3aaaaazmbduh5nwvcvpgrihhnjxacz2jvzu3prrdqewo3vmxkhu5yd3fa3eil56fyh5l7ojimghwbf2o6ri7cmppr34qflr5o4w6s5fekxhdt3qvlgsw5yp5wrmjjffhph5czd5kzoo7yyg5x3wgxxzdvwtuom2c5olao62ep77b7wqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactwxn7tsxj2nh6skwbghycguqfj7xrpegeporex5ebctynbgbl73mcs3dmxesuoke5hyqe6qmsdwy6ctqg6vb4cldzswriymxconeesaarmcwjw6vqh7bdzd34ftjfcmxu2l423hefx7j3qblqmtsbo3sxlq2qaaudfa3cpzk5rcfvnb3wioufku7togz4kntyjzazp3qi5x3h63tweiaaikvquz5otrlhusf45w7o47ejpb4czdjhxgkuszrxslkyeedrljkmaajnqklmns4skrzitu7cat2bsio3dykoa32uhqjmpgk2fdbs4jzuqsiaa6k7uub7uqlamlqi2oduautemch242scu7cfor6kedxs6mm3uwjsmaaaae4gg33emvrv63tbnvstumz2mnzhglddn5sgky27obqxeylnom5dqortgezc2mzngeycyy3spfyhi5dfpb2f62dbonudumzshkl7fjw5sp7x3yw4sdhze6qf7zgsjocpqtwl2gj5o6vufvixto3u2lddoj4xa5dumv4hix3sn5xxix3imfzwqortgi5fhno37hfotu2p5evmcmpqenjakt7pc6imi65cjp2icfhq2cmcx7rmnzswkzdfmrpxg2dbojsxgorrhizsy3tvnvpxgzlhnvsw45dthiytumjmonswo3lfnz2f643jpjstumz2gmyteldtnbqxezk7ojxw65c7nbqxg2b2gmzdubzmius26hljzu4j7gq5hdshwueqcfjc2bmveiyqbdxgyejetzovfrzws6tfhiztumzrgawhiyljnrpwg33emvrv64dbojqw24z2ha5dgmjsfuzs2mjqfr2g65dbnrpxg2dbojsxgorshiytalaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadusyxmwhtnfdeewwgxd25fwixycfdcy46ifqv4dhga23fko6dbl4ywo2d27n3zh3wd6zumhupvmtgspqrh6t7wbsghruzqd3imbo2tojfplbwi"),
|
3: base32.a2b(b"aaaaaaiaaacyeaaaaaaqaaaaaeaaaadiaaaaa2aaaaaciaaaacgaaaaavqaaaagmaaaab3aaaaazmbduh5nwvcvpgrihhnjxacz2jvzu3prrdqewo3vmxkhu5yd3fa3eil56fyh5l7ojimghwbf2o6ri7cmppr34qflr5o4w6s5fekxhdt3qvlgsw5yp5wrmjjffhph5czd5kzoo7yyg5x3wgxxzdvwtuom2c5olao62ep77b7wqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactwxn7tsxj2nh6skwbghycguqfj7xrpegeporex5ebctynbgbl73mcs3dmxesuoke5hyqe6qmsdwy6ctqg6vb4cldzswriymxconeesaarmcwjw6vqh7bdzd34ftjfcmxu2l423hefx7j3qblqmtsbo3sxlq2qaaudfa3cpzk5rcfvnb3wioufku7togz4kntyjzazp3qi5x3h63tweiaaikvquz5otrlhusf45w7o47ejpb4czdjhxgkuszrxslkyeedrljkmaajnqklmns4skrzitu7cat2bsio3dykoa32uhqjmpgk2fdbs4jzuqsiaa6k7uub7uqlamlqi2oduautemch242scu7cfor6kedxs6mm3uwjsmaaaae4gg33emvrv63tbnvstumz2mnzhglddn5sgky27obqxeylnom5dqortgezc2mzngeycyy3spfyhi5dfpb2f62dbonudumzshkl7fjw5sp7x3yw4sdhze6qf7zgsjocpqtwl2gj5o6vufvixto3u2lddoj4xa5dumv4hix3sn5xxix3imfzwqortgi5fhno37hfotu2p5evmcmpqenjakt7pc6imi65cjp2icfhq2cmcx7rmnzswkzdfmrpxg2dbojsxgorrhizsy3tvnvpxgzlhnvsw45dthiytumjmonswo3lfnz2f643jpjstumz2gmyteldtnbqxezk7ojxw65c7nbqxg2b2gmzdubzmius26hljzu4j7gq5hdshwueqcfjc2bmveiyqbdxgyejetzovfrzws6tfhiztumzrgawhiyljnrpwg33emvrv64dbojqw24z2ha5dgmjsfuzs2mjqfr2g65dbnrpxg2dbojsxgorshiytalaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadusyxmwhtnfdeewwgxd25fwixycfdcy46ifqv4dhga23fko6dbl4ywo2d27n3zh3wd6zumhupvmtgspqrh6t7wbsghruzqd3imbo2tojfplbwi"),
|
||||||
8: base32.a2b("aaaaaaiaaacyeaaaaaaqaaaaaeaaaadiaaaaa2aaaaaciaaaacgaaaaavqaaaagmaaaab3aaaaaznjzqcxwyhgwlcpzvfb2berhoyw47h72gkzofwgksryqd4r6xlyougvyg4p3wkz7u37zllskeswuuh4w2rylbxecomnmqfv7n5ex3thjzq7ykr7gjkvq3kmrlhmxu3wnsr4ipsdn546btavjzc6yppoii2mxgnnk4qbxqrltaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactwxn7tsxj2nh6skwbghycguqfj7xrpegeporex5ebctynbgbl72kfatp33ianoqvg6mdd4vaxa27lo6vpugbcvanhskaqq2kewn6kwaayg3gxuvrj4qpxwjhatgb3rycusa7zoc2jsrybw6saix5n6wcpcpmqaamxjsc6bwv4w4or2oylltmsbfbobvmenj3sa6lnq6iy4tugsnv72eaaybvqu3gmlomi3dnf2tum3hoseavpesyia2i2wqgwbmbtrgmotu6oaadirzs2idl54toffh4a2hehvg2e3zoed4dr6pcdpuqpnz2knte7gqqac6kfatp33ianoqvg6mdd4vaxa27lo6vpugbcvanhskaqq2kewn6kwaaaae4gg33emvrv63tbnvstumz2mnzhglddn5sgky27obqxeylnom5dqortgezc2mzngeycyy3spfyhi5dfpb2f62dbonudumzshkl7fjw5sp7x3yw4sdhze6qf7zgsjocpqtwl2gj5o6vufvixto3u2lddoj4xa5dumv4hix3sn5xxix3imfzwqortgi5fhno37hfotu2p5evmcmpqenjakt7pc6imi65cjp2icfhq2cmcx7rmnzswkzdfmrpxg2dbojsxgorrhizsy3tvnvpxgzlhnvsw45dthiytumjmonswo3lfnz2f643jpjstumz2gmyteldtnbqxezk7ojxw65c7nbqxg2b2gmzdubzmius26hljzu4j7gq5hdshwueqcfjc2bmveiyqbdxgyejetzovfrzws6tfhiztumzrgawhiyljnrpwg33emvrv64dbojqw24z2ha5dgmjsfuzs2mjqfr2g65dbnrpxg2dbojsxgorshiytalaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadusyxmwhtnfdeewwgxd25fwixycfdcy46ifqv4dhga23fko6dbl4ywo2d27n3zh3wd6zumhupvmtgspqrh6t7wbsghruzqd3imbo2tojfplbwi"),
|
8: base32.a2b(b"aaaaaaiaaacyeaaaaaaqaaaaaeaaaadiaaaaa2aaaaaciaaaacgaaaaavqaaaagmaaaab3aaaaaznjzqcxwyhgwlcpzvfb2berhoyw47h72gkzofwgksryqd4r6xlyougvyg4p3wkz7u37zllskeswuuh4w2rylbxecomnmqfv7n5ex3thjzq7ykr7gjkvq3kmrlhmxu3wnsr4ipsdn546btavjzc6yppoii2mxgnnk4qbxqrltaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactwxn7tsxj2nh6skwbghycguqfj7xrpegeporex5ebctynbgbl72kfatp33ianoqvg6mdd4vaxa27lo6vpugbcvanhskaqq2kewn6kwaayg3gxuvrj4qpxwjhatgb3rycusa7zoc2jsrybw6saix5n6wcpcpmqaamxjsc6bwv4w4or2oylltmsbfbobvmenj3sa6lnq6iy4tugsnv72eaaybvqu3gmlomi3dnf2tum3hoseavpesyia2i2wqgwbmbtrgmotu6oaadirzs2idl54toffh4a2hehvg2e3zoed4dr6pcdpuqpnz2knte7gqqac6kfatp33ianoqvg6mdd4vaxa27lo6vpugbcvanhskaqq2kewn6kwaaaae4gg33emvrv63tbnvstumz2mnzhglddn5sgky27obqxeylnom5dqortgezc2mzngeycyy3spfyhi5dfpb2f62dbonudumzshkl7fjw5sp7x3yw4sdhze6qf7zgsjocpqtwl2gj5o6vufvixto3u2lddoj4xa5dumv4hix3sn5xxix3imfzwqortgi5fhno37hfotu2p5evmcmpqenjakt7pc6imi65cjp2icfhq2cmcx7rmnzswkzdfmrpxg2dbojsxgorrhizsy3tvnvpxgzlhnvsw45dthiytumjmonswo3lfnz2f643jpjstumz2gmyteldtnbqxezk7ojxw65c7nbqxg2b2gmzdubzmius26hljzu4j7gq5hdshwueqcfjc2bmveiyqbdxgyejetzovfrzws6tfhiztumzrgawhiyljnrpwg33emvrv64dbojqw24z2ha5dgmjsfuzs2mjqfr2g65dbnrpxg2dbojsxgorshiytalaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadusyxmwhtnfdeewwgxd25fwixycfdcy46ifqv4dhga23fko6dbl4ywo2d27n3zh3wd6zumhupvmtgspqrh6t7wbsghruzqd3imbo2tojfplbwi"),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
mutable_uri = "URI:SSK:vfvcbdfbszyrsaxchgevhmmlii:euw4iw7bbnkrrwpzuburbhppuxhc3gwxv26f6imekhz7zyw2ojnq"
|
mutable_uri = b"URI:SSK:vfvcbdfbszyrsaxchgevhmmlii:euw4iw7bbnkrrwpzuburbhppuxhc3gwxv26f6imekhz7zyw2ojnq"
|
||||||
mutable_shares = {
|
mutable_shares = {
|
||||||
0: { # client[0]
|
0: { # client[0]
|
||||||
2: base32.a2b("krqwq33febwxk5dbmjwgkiddn5xhiyljnzsxeidwgefhkckeaohgreckgxome2uhcps464pzydv5wsywald7wthurw2dp6qxtkeb5vtswoeshuyno24v5oble7xb4j6ij7wwqriaaaaaaaaabb5aaaaaaaaaacsoaaaaaakjl2ynu3wrm2mwdv3syv4r34b5mklbtjuv5i5bzcuiwgfnl4wtpombwn7l7ugdvv2xut7hwbttcjfsacuhc7ipf43gvrgrt5vj7hau52uenoywreckgxome2uhcps464pzydv5wsywaldqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarybcjqw7lbehfrbu7pwx26vvv3mbjprnqup7q7wxmdsoyiqaqzgbtv6cplrrgpzbnptsoqz7imnauamfaaaaaaaaaaamgaaaaaaaaaaaymaaaaghqaaacr4aaaayxaaaagnyaaaaaaaaaao4qaaaaaaaaacd2gcbacibqbudaskugjcdpodibaeaqkaadqiaq2abqqiaqqaucaeaqbvkghg3s5ivqiq4uiajdzagl7iqhz2uxwj6aqk47oscyqxyljmxkapldxhxigum2ejxflnps3yrxwwehop2zairilrouid5s6wxgnoqg2vq7rx77icxfnx7mq65niuknra3tezhpndwo7pdxtvtci645p4umyhdh5gp3kbdpypphvouaql662r6ufigp4wwm6emrsavlontn4wttg6lv7bcmq6ojw5utpvz3agoenovrkndncjzxog7sp2w7l6jkmzgfxd2asxos5khkjbxbuhgkd6j5yqlzsmk3kq67engtlgyd7hxk7nedw73bq2bs4353wtler23poucntgve22acfxdbyj2f6q2saj2agu2ptfk364d3zayddffxkcah4olnkczjonselwwrvdcu3vch3licaeirogosgsui3y4ovcyzleurbiunp7fsfk2fgmiek7b3jogvrhj4snvkpqjfh2w2lqnkvqvuoojmgrn6sll354mpomajbtlsv6fuguzgsxsm3l2ehxdxfdv6kcoyogaa5raetooahunf4ltvfdb4d7mwgpj4pg7tmcw55ku5vgx7tjqkdkuyq2uvhavkbsbujsrcfzve5ekuhftxm7nmtomibrblbwyxcr5mcy6qqwx66lrhejmgewrig74nzpriualhw4g22qaw423qeezqn6irea3vlgc3foz4egf6irincownoq7utv643vmtoueebigwrl6nehbos3ipsdx44tmucpvyui2jzgfulb5mrrcjuycmuzfigu6tf25lbysqn7n7smhqniddgctjt573rtd6o63wiaactacm7dw7giohzcgwe4okbijnmzlacetmfjjbasrd6whexjmwkaiaabdm4cpjolak4m47telnokjaxwodj7ont7n7vffnmhkzp3lyshkh3qaaohafr65kctby6wa34bjpnviviiwmwq5mft3yho4tmslaarpcg6biaajlxuwwafut5a6dsr7lq5fkmiik7icppic5ffjjmqaud4y746q2rzd42k42oitzukawdl2fupkoqcztfu7qf2flp55xh4lm6rzpdbb7gtnx4kaffym36rboalf2tbmatt46ra6igvjnvwmig6ivf6gqrhcietf373xrbm3bpeecz7luv7kv76i7pwa5xtubga37vnlu6hspejpsenxiptd23ipri7u5w7lz67mdjfrpahtp5j46obg4ct7c5lelfskzqw5hq7x7kd7pbcgq3gjbv53amzxjelwgxpf6ni74zb6aixhjjllivkthks6df52kvobtcnscytmjrrfbekvwmhtbcke2cgcyaj2cra7xmnd4bw2xe2qki5kycopo45ekfyxwzsmxuyxvjzqklnqjwm3j3gwcm75ftnrsvbj33w6eyr4dbz2tewum7vfsyfbb3ojw5ujtn22jxpr4nkmkqup6z7ukpp4cdxwyge2psc5suaxaltmp23gbawoo3qjeo44hgwgtkge2oowox3fpxwxkckaqgrxilfeyxmjp4cwf2rhpkbwtveqkukchv3u5rfkykwfj5zhleu3obsif6ldfclaef32wjpe5d6ddh2grdx2yt6tuhw53t6zuuumlw6t6i3e2ev7nh36e4shwbn3ew2bbahn6imgb5sismfttf5cdlr5kw6wvjoaqiaiz2onxecfx735dvon7epthnklq67tnqj4fvcwechbvmnkpiwd5fd36dirpshc7i7zj3rcr5y3kzps5nfnfnik27gdgemfn27iblcjh5bpkio6sr375bmxbh6fshbo7cvjzsdsirsafnbjzgl6ycqczwbacj5sxwgrzl6qbdhfbzev5fzutznzbasejqdjm3qxsdcuqvqau3kih2anr2itgmr44wmwtsk6bd42m2j436ptslaugmbbvtbzsukeqytkse7niovlilyfssn3ipzkqtclmetqrxxn7h56xn2ju7pjnuamd6ijfawn2jpjsrmnawaozeniosvhgovftoj24dl77ytdkxdl7ogappnlgkqsjyy43urtnj6tqf2psfptkbzyx4nu3rzgsqqi5ybx3pu6cvt6de67xutdz566wrkp2ymy5n7tqchmw77ss532noqcbfxv6quum6jmeed3exasdapvid6bilwzm5dcnutkcxktmsdryqopw5ntws3tnbd7um27clmxkgl2uinwzvv4tmo4axbj5zmgfd6sy2fiw6efdwjcyj4awdx3peuxcyh3ccee63w2nqaltierdrevl3f3hnjsrdrl4aosd23szhhaimhg2mjuocottcdsraoczh3waoyxx2skunaphe6w5gutu2z7cag3cx4pgsspfmspphuunzx357x6l36hj3tdys727rhawfwc4wc4ytgts4nrxlxl3xxzffunlhjhzj5guxljwxfrxwjfsg5c67pg3js7gvfqmpson6rjgiuwbsklranwhauq74lbesavftdzf7y3x5zwbi4uu6q2vqimbkttm7k6ycttsgknej2ylkwdxgtut7wecpepnb527pblj3vuzldjt3whsmstax536plulalxtxmvj6vvg4phofyaidhxhhkl4dfb6oabp3fi55jt77pw3jl55pwbsimjpdanuenll2xxctr6swaimuaqk4wvqa6rbgow3onr74v4alkuukc2tlmorvsjpgaazpun6pbfyorazzarhc2r7fjt55pmosowrqcpdwl2q34hcco2f3icmpktchxdvtpmitufnplqaifbtlktkpo7b22244n6dkmxtgcnxtixsit57uhh7rc5rqezjz7pfd7ojhrui5bcdzb7bo2nbo6o24lpwbg4bmqgbqpbwclq6kglgxefryxlkqydillki3545vcrelfw6reszml6emuyjscx377on2qpq26j5jrh5xmbwmpcyq6sewanlbmwwk2vqhq5zunbcyd6h5z3ms3bgfn7lflvev5vwmjnv5nzbgrmpamy453zuvy6xc6jp7tqgpmrlxup7suptejbacm6rdurdhcaori6i25wylgaikfov4dfgeswxdeerogy2m5tbzsdlr7pfhchd4wnokuipfwjzejxiruj5cljm66hvn47j3eseys3nsi6xdh566jgap5s5e7ytdkkhh5lsuv47oose4luozz427dzk577jccjg3n7b4myd565edmsywol3hgh2i54lcya6saaaaaaa"),
|
2: base32.a2b(b"krqwq33febwxk5dbmjwgkiddn5xhiyljnzsxeidwgefhkckeaohgreckgxome2uhcps464pzydv5wsywald7wthurw2dp6qxtkeb5vtswoeshuyno24v5oble7xb4j6ij7wwqriaaaaaaaaabb5aaaaaaaaaacsoaaaaaakjl2ynu3wrm2mwdv3syv4r34b5mklbtjuv5i5bzcuiwgfnl4wtpombwn7l7ugdvv2xut7hwbttcjfsacuhc7ipf43gvrgrt5vj7hau52uenoywreckgxome2uhcps464pzydv5wsywaldqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarybcjqw7lbehfrbu7pwx26vvv3mbjprnqup7q7wxmdsoyiqaqzgbtv6cplrrgpzbnptsoqz7imnauamfaaaaaaaaaaamgaaaaaaaaaaaymaaaaghqaaacr4aaaayxaaaagnyaaaaaaaaaao4qaaaaaaaaacd2gcbacibqbudaskugjcdpodibaeaqkaadqiaq2abqqiaqqaucaeaqbvkghg3s5ivqiq4uiajdzagl7iqhz2uxwj6aqk47oscyqxyljmxkapldxhxigum2ejxflnps3yrxwwehop2zairilrouid5s6wxgnoqg2vq7rx77icxfnx7mq65niuknra3tezhpndwo7pdxtvtci645p4umyhdh5gp3kbdpypphvouaql662r6ufigp4wwm6emrsavlontn4wttg6lv7bcmq6ojw5utpvz3agoenovrkndncjzxog7sp2w7l6jkmzgfxd2asxos5khkjbxbuhgkd6j5yqlzsmk3kq67engtlgyd7hxk7nedw73bq2bs4353wtler23poucntgve22acfxdbyj2f6q2saj2agu2ptfk364d3zayddffxkcah4olnkczjonselwwrvdcu3vch3licaeirogosgsui3y4ovcyzleurbiunp7fsfk2fgmiek7b3jogvrhj4snvkpqjfh2w2lqnkvqvuoojmgrn6sll354mpomajbtlsv6fuguzgsxsm3l2ehxdxfdv6kcoyogaa5raetooahunf4ltvfdb4d7mwgpj4pg7tmcw55ku5vgx7tjqkdkuyq2uvhavkbsbujsrcfzve5ekuhftxm7nmtomibrblbwyxcr5mcy6qqwx66lrhejmgewrig74nzpriualhw4g22qaw423qeezqn6irea3vlgc3foz4egf6irincownoq7utv643vmtoueebigwrl6nehbos3ipsdx44tmucpvyui2jzgfulb5mrrcjuycmuzfigu6tf25lbysqn7n7smhqniddgctjt573rtd6o63wiaactacm7dw7giohzcgwe4okbijnmzlacetmfjjbasrd6whexjmwkaiaabdm4cpjolak4m47telnokjaxwodj7ont7n7vffnmhkzp3lyshkh3qaaohafr65kctby6wa34bjpnviviiwmwq5mft3yho4tmslaarpcg6biaajlxuwwafut5a6dsr7lq5fkmiik7icppic5ffjjmqaud4y746q2rzd42k42oitzukawdl2fupkoqcztfu7qf2flp55xh4lm6rzpdbb7gtnx4kaffym36rboalf2tbmatt46ra6igvjnvwmig6ivf6gqrhcietf373xrbm3bpeecz7luv7kv76i7pwa5xtubga37vnlu6hspejpsenxiptd23ipri7u5w7lz67mdjfrpahtp5j46obg4ct7c5lelfskzqw5hq7x7kd7pbcgq3gjbv53amzxjelwgxpf6ni74zb6aixhjjllivkthks6df52kvobtcnscytmjrrfbekvwmhtbcke2cgcyaj2cra7xmnd4bw2xe2qki5kycopo45ekfyxwzsmxuyxvjzqklnqjwm3j3gwcm75ftnrsvbj33w6eyr4dbz2tewum7vfsyfbb3ojw5ujtn22jxpr4nkmkqup6z7ukpp4cdxwyge2psc5suaxaltmp23gbawoo3qjeo44hgwgtkge2oowox3fpxwxkckaqgrxilfeyxmjp4cwf2rhpkbwtveqkukchv3u5rfkykwfj5zhleu3obsif6ldfclaef32wjpe5d6ddh2grdx2yt6tuhw53t6zuuumlw6t6i3e2ev7nh36e4shwbn3ew2bbahn6imgb5sismfttf5cdlr5kw6wvjoaqiaiz2onxecfx735dvon7epthnklq67tnqj4fvcwechbvmnkpiwd5fd36dirpshc7i7zj3rcr5y3kzps5nfnfnik27gdgemfn27iblcjh5bpkio6sr375bmxbh6fshbo7cvjzsdsirsafnbjzgl6ycqczwbacj5sxwgrzl6qbdhfbzev5fzutznzbasejqdjm3qxsdcuqvqau3kih2anr2itgmr44wmwtsk6bd42m2j436ptslaugmbbvtbzsukeqytkse7niovlilyfssn3ipzkqtclmetqrxxn7h56xn2ju7pjnuamd6ijfawn2jpjsrmnawaozeniosvhgovftoj24dl77ytdkxdl7ogappnlgkqsjyy43urtnj6tqf2psfptkbzyx4nu3rzgsqqi5ybx3pu6cvt6de67xutdz566wrkp2ymy5n7tqchmw77ss532noqcbfxv6quum6jmeed3exasdapvid6bilwzm5dcnutkcxktmsdryqopw5ntws3tnbd7um27clmxkgl2uinwzvv4tmo4axbj5zmgfd6sy2fiw6efdwjcyj4awdx3peuxcyh3ccee63w2nqaltierdrevl3f3hnjsrdrl4aosd23szhhaimhg2mjuocottcdsraoczh3waoyxx2skunaphe6w5gutu2z7cag3cx4pgsspfmspphuunzx357x6l36hj3tdys727rhawfwc4wc4ytgts4nrxlxl3xxzffunlhjhzj5guxljwxfrxwjfsg5c67pg3js7gvfqmpson6rjgiuwbsklranwhauq74lbesavftdzf7y3x5zwbi4uu6q2vqimbkttm7k6ycttsgknej2ylkwdxgtut7wecpepnb527pblj3vuzldjt3whsmstax536plulalxtxmvj6vvg4phofyaidhxhhkl4dfb6oabp3fi55jt77pw3jl55pwbsimjpdanuenll2xxctr6swaimuaqk4wvqa6rbgow3onr74v4alkuukc2tlmorvsjpgaazpun6pbfyorazzarhc2r7fjt55pmosowrqcpdwl2q34hcco2f3icmpktchxdvtpmitufnplqaifbtlktkpo7b22244n6dkmxtgcnxtixsit57uhh7rc5rqezjz7pfd7ojhrui5bcdzb7bo2nbo6o24lpwbg4bmqgbqpbwclq6kglgxefryxlkqydillki3545vcrelfw6reszml6emuyjscx377on2qpq26j5jrh5xmbwmpcyq6sewanlbmwwk2vqhq5zunbcyd6h5z3ms3bgfn7lflvev5vwmjnv5nzbgrmpamy453zuvy6xc6jp7tqgpmrlxup7suptejbacm6rdurdhcaori6i25wylgaikfov4dfgeswxdeerogy2m5tbzsdlr7pfhchd4wnokuipfwjzejxiruj5cljm66hvn47j3eseys3nsi6xdh566jgap5s5e7ytdkkhh5lsuv47oose4luozz427dzk577jccjg3n7b4myd565edmsywol3hgh2i54lcya6saaaaaaa"),
|
||||||
7: base32.a2b("krqwq33febwxk5dbmjwgkiddn5xhiyljnzsxeidwgefhkckeaohgreckgxome2uhcps464pzydv5wsywald7wthurw2dp6qxtkeb5vtswoeshuyno24v5oble7xb4j6ij7wwqriaaaaaaaaabb5aaaaaaaaaacsoaaaaaakjl2ynu3wrm2mwdv3syv4r34b5mklbtjuv5i5bzcuiwgfnl4wtpombwn7l7ugdvv2xut7hwbttcjfsacuhc7ipf43gvrgrt5vj7hau52uenoywreckgxome2uhcps464pzydv5wsywaldqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarybcjqw7lbehfrbu7pwx26vvv3mbjprnqup7q7wxmdsoyiqaqzgbtv6cplrrgpzbnptsoqz7imnauamfaaaaaaaaaaamgaaaaaaaaaaaymaaaaghqaaacr4aaaayxaaaagnyaaaaaaaaaao4qaaaaaaaaacd2gcbacibqbudaskugjcdpodibaeaqkaadqiaq2abqqiaqqaucaeaqbvkghg3s5ivqiq4uiajdzagl7iqhz2uxwj6aqk47oscyqxyljmxkapldxhxigum2ejxflnps3yrxwwehop2zairilrouid5s6wxgnoqg2vq7rx77icxfnx7mq65niuknra3tezhpndwo7pdxtvtci645p4umyhdh5gp3kbdpypphvouaql662r6ufigp4wwm6emrsavlontn4wttg6lv7bcmq6ojw5utpvz3agoenovrkndncjzxog7sp2w7l6jkmzgfxd2asxos5khkjbxbuhgkd6j5yqlzsmk3kq67engtlgyd7hxk7nedw73bq2bs4353wtler23poucntgve22acfxdbyj2f6q2saj2agu2ptfk364d3zayddffxkcah4olnkczjonselwwrvdcu3vch3licaeirogosgsui3y4ovcyzleurbiunp7fsfk2fgmiek7b3jogvrhj4snvkpqjfh2w2lqnkvqvuoojmgrn6sll354mpomajbtlsv6fuguzgsxsm3l2ehxdxfdv6kcoyogaa5raetooahunf4ltvfdb4d7mwgpj4pg7tmcw55ku5vgx7tjqkdkuyq2uvhavkbsbujsrcfzve5ekuhftxm7nmtomibrblbwyxcr5mcy6qqwx66lrhejmgewrig74nzpriualhw4g22qaw423qeezqn6irea3vlgc3foz4egf6irincownoq7utv643vmtoueebigwrl6nehbos3ipsdx44tmucpvyui2jzgfulb5mrrcjuycmuzfigu6tf25lbysqn7n7smhqniddgctjt573rtd6o63wiaactacm7dw7giohzcgwe4okbijnmzlacetmfjjbasrd6whexjmwkaiaaazuum3xriq54h5v6afcrrl3kkbd46oizwulc5fbslmblxfc3ldyyqaaszc7rkciv6rhwt5gbgnl5u54ihnqrfyuh7s54r2444mrhcwgizieaak4ap2xhvuz664fw3kayv7z5vawqs7skj6frzp3ihmk7js3tr7cwpnbfwoefuyn6bqkj5kssx3rvvffqgd3mhb7pbtegk6qfvsopvzmsiftabaykw3qitiqcv2wwfvdud5lkbjigatrf4ndeejsij5ab3eyaqqgxfiyxtv674qwltgynickeznu5el6uhs2k75hq2rsxhco2kmxw4didbdjodmjf2nrne63du76fd6laa7ng7zq4i7bx2xtohfrgwlxls6h7ibfsbybdz46sow3tn4vao3ulciz75kfbb62jrz3omvnihr2jwthks6df52kvobtcnscytmjrrfbekvwmhtbcke2cgcyaj2cra7xmnd4bw2xe2qki5kycopo45ekfyxwzsmxuyxvjzqklnqjwm3j3gwcm75ftnrsvbj33w6eyr4dbz2tewum7vfsyfbb3ojw5ujtn22jxpr4nkmkqup6z7ukpp4cdxwyge2psc5suaxaltmp23gbawoo3qjeo44hgwgtkge2oowox3fpxwxkckaqgrxilfeyxmjp4cwf2rhpkbwtveqkukchv3u5rfkykwfj5zhleu3obsif6ldfclaef32wjpe5d6ddh2grdx2yt6tuhw53t6zuuumlw6t6i3e2ev7nh36e4shwbn3ew2bbahn6imgb5sismfttf5cdlr5kw6wvjoaqiaiz2onxecfx735dvon7epthnklq67tnqj4fvcwechbvmnkpiwd5fd36dirpshc7i7zj3rcr5y3kzps5nfnfnik27gdgemfn27iblcjh5bpkio6sr375bmxbh6fshbo7cvjzsdsirsafnbjzgl6ycqczwbacj5sxwgrzl6qbdhfbzev5fzutznzbasejqdjm3qxsdcuqvqau3kih2anr2itgmr44wmwtsk6bd42m2j436ptslaugmbbvtbzsukeqytkse7niovlilyfssn3ipzkqtclmetqrxxn7h56xn2ju7pjnuamd6ijfawn2jpjsrmnawaozeniosvhgovftoj24dl77ytdkxdl7ogappnlgkqsjyy43urtnj6tqf2psfptkbzyx4nu3rzgsqqi5ybx3pu6cvt6de67xutdz566wrkp2ymy5n7tqchmw77ss532noqcbfxv6quum6jmeed3exasdapvid6bilwzm5dcnutkcxktmsdryqopw5ntws3tnbd7um27clmxkgl2uinwzvv4tmo4axbj5zmgfd6sy2fiw6efdwjcyj4awdx3peuxcyh3ccee63w2nqaltierdrevl3f3hnjsrdrl4aosd23szhhaimhg2mjuocottcdsraoczh3waoyxx2skunaphe6w5gutu2z7cag3cx4pgsspfmspphuunzx357x6l36hj3tdys727rhawfwc4wc4ytgts4nrxlxl3xxzffunlhjhzj5guxljwxfrxwjfsg5c67pg3js7gvfqmpson6rjgiuwbsklranwhauq74lbesavftdzf7y3x5zwbi4uu6q2vqimbkttm7k6ycttsgknej2ylkwdxgtut7wecpepnb527pblj3vuzldjt3whsmstax536plulalxtxmvj6vvg4phofyaidhxhhkl4dfb6oabp3fi55jt77pw3jl55pwbsimjpdanuenll2xxctr6swaimuaqk4wvqa6rbgow3onr74v4alkuukc2tlmorvsjpgaazpun6pbfyorazzarhc2r7fjt55pmosowrqcpdwl2q34hcco2f3icmpktchxdvtpmitufnplqaifbtlktkpo7b22244n6dkmxtgcnxtixsit57uhh7rc5rqezjz7pfd7ojhrui5bcdzb7bo2nbo6o24lpwbg4bmqgbqpbwclq6kglgxefryxlkqydillki3545vcrelfw6reszml6emuyjscx377on2qpq26j5jrh5xmbwmpcyq6sewanlbmwwk2vqhq5zunbcyd6h5z3ms3bgfn7lflvev5vwmjnv5nzbgrmpamy453zuvy6xc6jp7tqgpmrlxup7suptejbacm6rdurdhcaori6i25wylgaikfov4dfgeswxdeerogy2m5tbzsdlr7pfhchd4wnokuipfwjzejxiruj5cljm66hvn47j3eseys3nsi6xdh566jgap5s5e7ytdkkhh5lsuv47oose4luozz427dzk577jccjg3n7b4myd565edmsywol3hgh2i54lcya6saaaaaaa"),
|
7: base32.a2b(b"krqwq33febwxk5dbmjwgkiddn5xhiyljnzsxeidwgefhkckeaohgreckgxome2uhcps464pzydv5wsywald7wthurw2dp6qxtkeb5vtswoeshuyno24v5oble7xb4j6ij7wwqriaaaaaaaaabb5aaaaaaaaaacsoaaaaaakjl2ynu3wrm2mwdv3syv4r34b5mklbtjuv5i5bzcuiwgfnl4wtpombwn7l7ugdvv2xut7hwbttcjfsacuhc7ipf43gvrgrt5vj7hau52uenoywreckgxome2uhcps464pzydv5wsywaldqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarybcjqw7lbehfrbu7pwx26vvv3mbjprnqup7q7wxmdsoyiqaqzgbtv6cplrrgpzbnptsoqz7imnauamfaaaaaaaaaaamgaaaaaaaaaaaymaaaaghqaaacr4aaaayxaaaagnyaaaaaaaaaao4qaaaaaaaaacd2gcbacibqbudaskugjcdpodibaeaqkaadqiaq2abqqiaqqaucaeaqbvkghg3s5ivqiq4uiajdzagl7iqhz2uxwj6aqk47oscyqxyljmxkapldxhxigum2ejxflnps3yrxwwehop2zairilrouid5s6wxgnoqg2vq7rx77icxfnx7mq65niuknra3tezhpndwo7pdxtvtci645p4umyhdh5gp3kbdpypphvouaql662r6ufigp4wwm6emrsavlontn4wttg6lv7bcmq6ojw5utpvz3agoenovrkndncjzxog7sp2w7l6jkmzgfxd2asxos5khkjbxbuhgkd6j5yqlzsmk3kq67engtlgyd7hxk7nedw73bq2bs4353wtler23poucntgve22acfxdbyj2f6q2saj2agu2ptfk364d3zayddffxkcah4olnkczjonselwwrvdcu3vch3licaeirogosgsui3y4ovcyzleurbiunp7fsfk2fgmiek7b3jogvrhj4snvkpqjfh2w2lqnkvqvuoojmgrn6sll354mpomajbtlsv6fuguzgsxsm3l2ehxdxfdv6kcoyogaa5raetooahunf4ltvfdb4d7mwgpj4pg7tmcw55ku5vgx7tjqkdkuyq2uvhavkbsbujsrcfzve5ekuhftxm7nmtomibrblbwyxcr5mcy6qqwx66lrhejmgewrig74nzpriualhw4g22qaw423qeezqn6irea3vlgc3foz4egf6irincownoq7utv643vmtoueebigwrl6nehbos3ipsdx44tmucpvyui2jzgfulb5mrrcjuycmuzfigu6tf25lbysqn7n7smhqniddgctjt573rtd6o63wiaactacm7dw7giohzcgwe4okbijnmzlacetmfjjbasrd6whexjmwkaiaaazuum3xriq54h5v6afcrrl3kkbd46oizwulc5fbslmblxfc3ldyyqaaszc7rkciv6rhwt5gbgnl5u54ihnqrfyuh7s54r2444mrhcwgizieaak4ap2xhvuz664fw3kayv7z5vawqs7skj6frzp3ihmk7js3tr7cwpnbfwoefuyn6bqkj5kssx3rvvffqgd3mhb7pbtegk6qfvsopvzmsiftabaykw3qitiqcv2wwfvdud5lkbjigatrf4ndeejsij5ab3eyaqqgxfiyxtv674qwltgynickeznu5el6uhs2k75hq2rsxhco2kmxw4didbdjodmjf2nrne63du76fd6laa7ng7zq4i7bx2xtohfrgwlxls6h7ibfsbybdz46sow3tn4vao3ulciz75kfbb62jrz3omvnihr2jwthks6df52kvobtcnscytmjrrfbekvwmhtbcke2cgcyaj2cra7xmnd4bw2xe2qki5kycopo45ekfyxwzsmxuyxvjzqklnqjwm3j3gwcm75ftnrsvbj33w6eyr4dbz2tewum7vfsyfbb3ojw5ujtn22jxpr4nkmkqup6z7ukpp4cdxwyge2psc5suaxaltmp23gbawoo3qjeo44hgwgtkge2oowox3fpxwxkckaqgrxilfeyxmjp4cwf2rhpkbwtveqkukchv3u5rfkykwfj5zhleu3obsif6ldfclaef32wjpe5d6ddh2grdx2yt6tuhw53t6zuuumlw6t6i3e2ev7nh36e4shwbn3ew2bbahn6imgb5sismfttf5cdlr5kw6wvjoaqiaiz2onxecfx735dvon7epthnklq67tnqj4fvcwechbvmnkpiwd5fd36dirpshc7i7zj3rcr5y3kzps5nfnfnik27gdgemfn27iblcjh5bpkio6sr375bmxbh6fshbo7cvjzsdsirsafnbjzgl6ycqczwbacj5sxwgrzl6qbdhfbzev5fzutznzbasejqdjm3qxsdcuqvqau3kih2anr2itgmr44wmwtsk6bd42m2j436ptslaugmbbvtbzsukeqytkse7niovlilyfssn3ipzkqtclmetqrxxn7h56xn2ju7pjnuamd6ijfawn2jpjsrmnawaozeniosvhgovftoj24dl77ytdkxdl7ogappnlgkqsjyy43urtnj6tqf2psfptkbzyx4nu3rzgsqqi5ybx3pu6cvt6de67xutdz566wrkp2ymy5n7tqchmw77ss532noqcbfxv6quum6jmeed3exasdapvid6bilwzm5dcnutkcxktmsdryqopw5ntws3tnbd7um27clmxkgl2uinwzvv4tmo4axbj5zmgfd6sy2fiw6efdwjcyj4awdx3peuxcyh3ccee63w2nqaltierdrevl3f3hnjsrdrl4aosd23szhhaimhg2mjuocottcdsraoczh3waoyxx2skunaphe6w5gutu2z7cag3cx4pgsspfmspphuunzx357x6l36hj3tdys727rhawfwc4wc4ytgts4nrxlxl3xxzffunlhjhzj5guxljwxfrxwjfsg5c67pg3js7gvfqmpson6rjgiuwbsklranwhauq74lbesavftdzf7y3x5zwbi4uu6q2vqimbkttm7k6ycttsgknej2ylkwdxgtut7wecpepnb527pblj3vuzldjt3whsmstax536plulalxtxmvj6vvg4phofyaidhxhhkl4dfb6oabp3fi55jt77pw3jl55pwbsimjpdanuenll2xxctr6swaimuaqk4wvqa6rbgow3onr74v4alkuukc2tlmorvsjpgaazpun6pbfyorazzarhc2r7fjt55pmosowrqcpdwl2q34hcco2f3icmpktchxdvtpmitufnplqaifbtlktkpo7b22244n6dkmxtgcnxtixsit57uhh7rc5rqezjz7pfd7ojhrui5bcdzb7bo2nbo6o24lpwbg4bmqgbqpbwclq6kglgxefryxlkqydillki3545vcrelfw6reszml6emuyjscx377on2qpq26j5jrh5xmbwmpcyq6sewanlbmwwk2vqhq5zunbcyd6h5z3ms3bgfn7lflvev5vwmjnv5nzbgrmpamy453zuvy6xc6jp7tqgpmrlxup7suptejbacm6rdurdhcaori6i25wylgaikfov4dfgeswxdeerogy2m5tbzsdlr7pfhchd4wnokuipfwjzejxiruj5cljm66hvn47j3eseys3nsi6xdh566jgap5s5e7ytdkkhh5lsuv47oose4luozz427dzk577jccjg3n7b4myd565edmsywol3hgh2i54lcya6saaaaaaa"),
|
||||||
},
|
},
|
||||||
1: { # client[1]
|
1: { # client[1]
|
||||||
3: base32.a2b("krqwq33febwxk5dbmjwgkiddn5xhiyljnzsxeidwgefhkckeaohm5tnwcmfsfmep4exoamss5lqyleq2ehahoduym5vgk37pmxx2xekzrtlzfvhapzb2fe3quv6tv3atr3g6ykqaaaaaaaaabb5aaaaaaaaaacsoaaaaaakjl2ynvx5mk74p2on26ax4rlp5jcoto5jkz3ndmgbmurhez4a5rbuyr55acbwlgbndlebsdyvlt4ttog767zqpoq3n2a4pra5va2o5zvbttlh45tnwcmfsfmep4exoamss5lqyleq2ehaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarybcjqw7lbehfrbu7pwx26vvv3mbjprnqup7q7wxmdsoyiqaqzgbtv6cplrrgpzbnptsoqz7imnauamfaaaaaaaaaaamgaaaaaaaaaaaymaaaaghqaaacr4aaaayxaaaagnyaaaaaaaaaao4qaaaaaaaaacd2gcbacibqbudaskugjcdpodibaeaqkaadqiaq2abqqiaqqaucaeaqbvkghg3s5ivqiq4uiajdzagl7iqhz2uxwj6aqk47oscyqxyljmxkapldxhxigum2ejxflnps3yrxwwehop2zairilrouid5s6wxgnoqg2vq7rx77icxfnx7mq65niuknra3tezhpndwo7pdxtvtci645p4umyhdh5gp3kbdpypphvouaql662r6ufigp4wwm6emrsavlontn4wttg6lv7bcmq6ojw5utpvz3agoenovrkndncjzxog7sp2w7l6jkmzgfxd2asxos5khkjbxbuhgkd6j5yqlzsmk3kq67engtlgyd7hxk7nedw73bq2bs4353wtler23poucntgve22acfxdbyj2f6q2saj2agu2ptfk364d3zayddffxkcah4olnkczjonselwwrvdcu3vch3licaeirogosgsui3y4ovcyzleurbiunp7fsfk2fgmiek7b3jogvrhj4snvkpqjfh2w2lqnkvqvuoojmgrn6sll354mpomajbtlsv6fuguzgsxsm3l2ehxdxfdv6kcoyogaa5raetooahunf4ltvfdb4d7mwgpj4pg7tmcw55ku5vgx7tjqkdkuyq2uvhavkbsbujsrcfzve5ekuhftxm7nmtomibrblbwyxcr5mcy6qqwx66lrhejmgewrig74nzpriualhw4g22qaw423qeezqn6irea3vlgc3foz4egf6irincownoq7utv643vmtoueebigwrl6nehbos3ipsdx44tmucpvyui2jzgfulb5mrrcjuycmuzfigu6tf25lbysqn7n7smhqniddgctjt573rtd6o63wiaactacm7dw7giohzcgwe4okbijnmzlacetmfjjbasrd6whexjmwkaiaabdm4cpjolak4m47telnokjaxwodj7ont7n7vffnmhkzp3lyshkh3qaaohafr65kctby6wa34bjpnviviiwmwq5mft3yho4tmslaarpcg6biaaixzuvzu4rhtiubmgxuli6u5aftglj7alukw733opywz5ds6gcd6nf32llac2j6qpbzi7vyosvgeefpubhxubossuuwiakb6mp6pini4rja473klkmi52lzfwofja7bb6pixgcxkwdaerc2irfpnrqwh5o2remu3iv3dtib75ku63cb6xzj4h53nmsguanjpganh3ow5yzovjcsezsj2cunyvlpva63zx5sudxe2zrtcu5zoty2tjzzlhodaz6rxe62ehbiktd4pmaodaz6ajsrohw7tdga2dpaftzbhadsolylgwgtbymenwthks6df52kvobtcnscytmjrrfbekvwmhtbcke2cgcyaj2cra7xmnd4bw2xe2qki5kycopo45ekfyxwzsmxuyxvjzqklnqjwm3j3gwcm75ftnrsvbj33w6eyr4dbz2tewum7vfsyfbb3ojw5ujtn22jxpr4nkmkqup6z7ukpp4cdxwyge2psc5suaxaltmp23gbawoo3qjeo44hgwgtkge2oowox3fpxwxkckaqgrxilfeyxmjp4cwf2rhpkbwtveqkukchv3u5rfkykwfj5zhleu3obsif6ldfclaef32wjpe5d6ddh2grdx2yt6tuhw53t6zuuumlw6t6i3e2ev7nh36e4shwbn3ew2bbahn6imgb5sismfttf5cdlr5kw6wvjoaqiaiz2onxecfx735dvon7epthnklq67tnqj4fvcwechbvmnkpiwd5fd36dirpshc7i7zj3rcr5y3kzps5nfnfnik27gdgemfn27iblcjh5bpkio6sr375bmxbh6fshbo7cvjzsdsirsafnbjzgl6ycqczwbacj5sxwgrzl6qbdhfbzev5fzutznzbasejqdjm3qxsdcuqvqau3kih2anr2itgmr44wmwtsk6bd42m2j436ptslaugmbbvtbzsukeqytkse7niovlilyfssn3ipzkqtclmetqrxxn7h56xn2ju7pjnuamd6ijfawn2jpjsrmnawaozeniosvhgovftoj24dl77ytdkxdl7ogappnlgkqsjyy43urtnj6tqf2psfptkbzyx4nu3rzgsqqi5ybx3pu6cvt6de67xutdz566wrkp2ymy5n7tqchmw77ss532noqcbfxv6quum6jmeed3exasdapvid6bilwzm5dcnutkcxktmsdryqopw5ntws3tnbd7um27clmxkgl2uinwzvv4tmo4axbj5zmgfd6sy2fiw6efdwjcyj4awdx3peuxcyh3ccee63w2nqaltierdrevl3f3hnjsrdrl4aosd23szhhaimhg2mjuocottcdsraoczh3waoyxx2skunaphe6w5gutu2z7cag3cx4pgsspfmspphuunzx357x6l36hj3tdys727rhawfwc4wc4ytgts4nrxlxl3xxzffunlhjhzj5guxljwxfrxwjfsg5c67pg3js7gvfqmpson6rjgiuwbsklranwhauq74lbesavftdzf7y3x5zwbi4uu6q2vqimbkttm7k6ycttsgknej2ylkwdxgtut7wecpepnb527pblj3vuzldjt3whsmstax536plulalxtxmvj6vvg4phofyaidhxhhkl4dfb6oabp3fi55jt77pw3jl55pwbsimjpdanuenll2xxctr6swaimuaqk4wvqa6rbgow3onr74v4alkuukc2tlmorvsjpgaazpun6pbfyorazzarhc2r7fjt55pmosowrqcpdwl2q34hcco2f3icmpktchxdvtpmitufnplqaifbtlktkpo7b22244n6dkmxtgcnxtixsit57uhh7rc5rqezjz7pfd7ojhrui5bcdzb7bo2nbo6o24lpwbg4bmqgbqpbwclq6kglgxefryxlkqydillki3545vcrelfw6reszml6emuyjscx377on2qpq26j5jrh5xmbwmpcyq6sewanlbmwwk2vqhq5zunbcyd6h5z3ms3bgfn7lflvev5vwmjnv5nzbgrmpamy453zuvy6xc6jp7tqgpmrlxup7suptejbacm6rdurdhcaori6i25wylgaikfov4dfgeswxdeerogy2m5tbzsdlr7pfhchd4wnokuipfwjzejxiruj5cljm66hvn47j3eseys3nsi6xdh566jgap5s5e7ytdkkhh5lsuv47oose4luozz427dzk577jccjg3n7b4myd565edmsywol3hgh2i54lcya6saaaaaaa"),
|
3: base32.a2b(b"krqwq33febwxk5dbmjwgkiddn5xhiyljnzsxeidwgefhkckeaohm5tnwcmfsfmep4exoamss5lqyleq2ehahoduym5vgk37pmxx2xekzrtlzfvhapzb2fe3quv6tv3atr3g6ykqaaaaaaaaabb5aaaaaaaaaacsoaaaaaakjl2ynvx5mk74p2on26ax4rlp5jcoto5jkz3ndmgbmurhez4a5rbuyr55acbwlgbndlebsdyvlt4ttog767zqpoq3n2a4pra5va2o5zvbttlh45tnwcmfsfmep4exoamss5lqyleq2ehaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarybcjqw7lbehfrbu7pwx26vvv3mbjprnqup7q7wxmdsoyiqaqzgbtv6cplrrgpzbnptsoqz7imnauamfaaaaaaaaaaamgaaaaaaaaaaaymaaaaghqaaacr4aaaayxaaaagnyaaaaaaaaaao4qaaaaaaaaacd2gcbacibqbudaskugjcdpodibaeaqkaadqiaq2abqqiaqqaucaeaqbvkghg3s5ivqiq4uiajdzagl7iqhz2uxwj6aqk47oscyqxyljmxkapldxhxigum2ejxflnps3yrxwwehop2zairilrouid5s6wxgnoqg2vq7rx77icxfnx7mq65niuknra3tezhpndwo7pdxtvtci645p4umyhdh5gp3kbdpypphvouaql662r6ufigp4wwm6emrsavlontn4wttg6lv7bcmq6ojw5utpvz3agoenovrkndncjzxog7sp2w7l6jkmzgfxd2asxos5khkjbxbuhgkd6j5yqlzsmk3kq67engtlgyd7hxk7nedw73bq2bs4353wtler23poucntgve22acfxdbyj2f6q2saj2agu2ptfk364d3zayddffxkcah4olnkczjonselwwrvdcu3vch3licaeirogosgsui3y4ovcyzleurbiunp7fsfk2fgmiek7b3jogvrhj4snvkpqjfh2w2lqnkvqvuoojmgrn6sll354mpomajbtlsv6fuguzgsxsm3l2ehxdxfdv6kcoyogaa5raetooahunf4ltvfdb4d7mwgpj4pg7tmcw55ku5vgx7tjqkdkuyq2uvhavkbsbujsrcfzve5ekuhftxm7nmtomibrblbwyxcr5mcy6qqwx66lrhejmgewrig74nzpriualhw4g22qaw423qeezqn6irea3vlgc3foz4egf6irincownoq7utv643vmtoueebigwrl6nehbos3ipsdx44tmucpvyui2jzgfulb5mrrcjuycmuzfigu6tf25lbysqn7n7smhqniddgctjt573rtd6o63wiaactacm7dw7giohzcgwe4okbijnmzlacetmfjjbasrd6whexjmwkaiaabdm4cpjolak4m47telnokjaxwodj7ont7n7vffnmhkzp3lyshkh3qaaohafr65kctby6wa34bjpnviviiwmwq5mft3yho4tmslaarpcg6biaaixzuvzu4rhtiubmgxuli6u5aftglj7alukw733opywz5ds6gcd6nf32llac2j6qpbzi7vyosvgeefpubhxubossuuwiakb6mp6pini4rja473klkmi52lzfwofja7bb6pixgcxkwdaerc2irfpnrqwh5o2remu3iv3dtib75ku63cb6xzj4h53nmsguanjpganh3ow5yzovjcsezsj2cunyvlpva63zx5sudxe2zrtcu5zoty2tjzzlhodaz6rxe62ehbiktd4pmaodaz6ajsrohw7tdga2dpaftzbhadsolylgwgtbymenwthks6df52kvobtcnscytmjrrfbekvwmhtbcke2cgcyaj2cra7xmnd4bw2xe2qki5kycopo45ekfyxwzsmxuyxvjzqklnqjwm3j3gwcm75ftnrsvbj33w6eyr4dbz2tewum7vfsyfbb3ojw5ujtn22jxpr4nkmkqup6z7ukpp4cdxwyge2psc5suaxaltmp23gbawoo3qjeo44hgwgtkge2oowox3fpxwxkckaqgrxilfeyxmjp4cwf2rhpkbwtveqkukchv3u5rfkykwfj5zhleu3obsif6ldfclaef32wjpe5d6ddh2grdx2yt6tuhw53t6zuuumlw6t6i3e2ev7nh36e4shwbn3ew2bbahn6imgb5sismfttf5cdlr5kw6wvjoaqiaiz2onxecfx735dvon7epthnklq67tnqj4fvcwechbvmnkpiwd5fd36dirpshc7i7zj3rcr5y3kzps5nfnfnik27gdgemfn27iblcjh5bpkio6sr375bmxbh6fshbo7cvjzsdsirsafnbjzgl6ycqczwbacj5sxwgrzl6qbdhfbzev5fzutznzbasejqdjm3qxsdcuqvqau3kih2anr2itgmr44wmwtsk6bd42m2j436ptslaugmbbvtbzsukeqytkse7niovlilyfssn3ipzkqtclmetqrxxn7h56xn2ju7pjnuamd6ijfawn2jpjsrmnawaozeniosvhgovftoj24dl77ytdkxdl7ogappnlgkqsjyy43urtnj6tqf2psfptkbzyx4nu3rzgsqqi5ybx3pu6cvt6de67xutdz566wrkp2ymy5n7tqchmw77ss532noqcbfxv6quum6jmeed3exasdapvid6bilwzm5dcnutkcxktmsdryqopw5ntws3tnbd7um27clmxkgl2uinwzvv4tmo4axbj5zmgfd6sy2fiw6efdwjcyj4awdx3peuxcyh3ccee63w2nqaltierdrevl3f3hnjsrdrl4aosd23szhhaimhg2mjuocottcdsraoczh3waoyxx2skunaphe6w5gutu2z7cag3cx4pgsspfmspphuunzx357x6l36hj3tdys727rhawfwc4wc4ytgts4nrxlxl3xxzffunlhjhzj5guxljwxfrxwjfsg5c67pg3js7gvfqmpson6rjgiuwbsklranwhauq74lbesavftdzf7y3x5zwbi4uu6q2vqimbkttm7k6ycttsgknej2ylkwdxgtut7wecpepnb527pblj3vuzldjt3whsmstax536plulalxtxmvj6vvg4phofyaidhxhhkl4dfb6oabp3fi55jt77pw3jl55pwbsimjpdanuenll2xxctr6swaimuaqk4wvqa6rbgow3onr74v4alkuukc2tlmorvsjpgaazpun6pbfyorazzarhc2r7fjt55pmosowrqcpdwl2q34hcco2f3icmpktchxdvtpmitufnplqaifbtlktkpo7b22244n6dkmxtgcnxtixsit57uhh7rc5rqezjz7pfd7ojhrui5bcdzb7bo2nbo6o24lpwbg4bmqgbqpbwclq6kglgxefryxlkqydillki3545vcrelfw6reszml6emuyjscx377on2qpq26j5jrh5xmbwmpcyq6sewanlbmwwk2vqhq5zunbcyd6h5z3ms3bgfn7lflvev5vwmjnv5nzbgrmpamy453zuvy6xc6jp7tqgpmrlxup7suptejbacm6rdurdhcaori6i25wylgaikfov4dfgeswxdeerogy2m5tbzsdlr7pfhchd4wnokuipfwjzejxiruj5cljm66hvn47j3eseys3nsi6xdh566jgap5s5e7ytdkkhh5lsuv47oose4luozz427dzk577jccjg3n7b4myd565edmsywol3hgh2i54lcya6saaaaaaa"),
|
||||||
8: base32.a2b("krqwq33febwxk5dbmjwgkiddn5xhiyljnzsxeidwgefhkckeaohm5tnwcmfsfmep4exoamss5lqyleq2ehahoduym5vgk37pmxx2xekzrtlzfvhapzb2fe3quv6tv3atr3g6ykqaaaaaaaaabb5aaaaaaaaaacsoaaaaaakjl2ynvx5mk74p2on26ax4rlp5jcoto5jkz3ndmgbmurhez4a5rbuyr55acbwlgbndlebsdyvlt4ttog767zqpoq3n2a4pra5va2o5zvbttlh45tnwcmfsfmep4exoamss5lqyleq2ehaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarybcjqw7lbehfrbu7pwx26vvv3mbjprnqup7q7wxmdsoyiqaqzgbtv6cplrrgpzbnptsoqz7imnauamfaaaaaaaaaaamgaaaaaaaaaaaymaaaaghqaaacr4aaaayxaaaagnyaaaaaaaaaao4qaaaaaaaaacd2gcbacibqbudaskugjcdpodibaeaqkaadqiaq2abqqiaqqaucaeaqbvkghg3s5ivqiq4uiajdzagl7iqhz2uxwj6aqk47oscyqxyljmxkapldxhxigum2ejxflnps3yrxwwehop2zairilrouid5s6wxgnoqg2vq7rx77icxfnx7mq65niuknra3tezhpndwo7pdxtvtci645p4umyhdh5gp3kbdpypphvouaql662r6ufigp4wwm6emrsavlontn4wttg6lv7bcmq6ojw5utpvz3agoenovrkndncjzxog7sp2w7l6jkmzgfxd2asxos5khkjbxbuhgkd6j5yqlzsmk3kq67engtlgyd7hxk7nedw73bq2bs4353wtler23poucntgve22acfxdbyj2f6q2saj2agu2ptfk364d3zayddffxkcah4olnkczjonselwwrvdcu3vch3licaeirogosgsui3y4ovcyzleurbiunp7fsfk2fgmiek7b3jogvrhj4snvkpqjfh2w2lqnkvqvuoojmgrn6sll354mpomajbtlsv6fuguzgsxsm3l2ehxdxfdv6kcoyogaa5raetooahunf4ltvfdb4d7mwgpj4pg7tmcw55ku5vgx7tjqkdkuyq2uvhavkbsbujsrcfzve5ekuhftxm7nmtomibrblbwyxcr5mcy6qqwx66lrhejmgewrig74nzpriualhw4g22qaw423qeezqn6irea3vlgc3foz4egf6irincownoq7utv643vmtoueebigwrl6nehbos3ipsdx44tmucpvyui2jzgfulb5mrrcjuycmuzfigu6tf25lbysqn7n7smhqniddgctjt573rtd6o63wiaabduzspufh6gomrp7sycuerhgl7ah3x3mpc6watmzlp6y23afmlxcaabui4znebv66jxcst6andsd2tncn4xcb6by7hrbx2ihw45fgzsptiiaaybvqu3gmlomi3dnf2tum3hoseavpesyia2i2wqgwbmbtrgmotu6oaamprqe6ozjrouoeltzhezhntop7wb6bbnnr3ak6x3ihvsjlz77gffkdet4sc63bxykwaikdyxwoehbrggxdu6qcwquzsnaltcgn52nyy4ypqbthfg4txtnznap6dktqtgtmtu7icooojppbwyi5c22uehbveptbuhbi7q3d4wuvsrptnd6wrhxwtlkxe4kurp4fey52p2v6urgephzxmaqfhm7pq3wxbi2uj5ourg65xnhbo4lrp7nzrdmk3svespmmitccvtwom6wtqefpp73j67zybiu4wrjjqt7vhip4ipuaezkmdy7feothks6df52kvobtcnscytmjrrfbekvwmhtbcke2cgcyaj2cra7xmnd4bw2xe2qki5kycopo45ekfyxwzsmxuyxvjzqklnqjwm3j3gwcm75ftnrsvbj33w6eyr4dbz2tewum7vfsyfbb3ojw5ujtn22jxpr4nkmkqup6z7ukpp4cdxwyge2psc5suaxaltmp23gbawoo3qjeo44hgwgtkge2oowox3fpxwxkckaqgrxilfeyxmjp4cwf2rhpkbwtveqkukchv3u5rfkykwfj5zhleu3obsif6ldfclaef32wjpe5d6ddh2grdx2yt6tuhw53t6zuuumlw6t6i3e2ev7nh36e4shwbn3ew2bbahn6imgb5sismfttf5cdlr5kw6wvjoaqiaiz2onxecfx735dvon7epthnklq67tnqj4fvcwechbvmnkpiwd5fd36dirpshc7i7zj3rcr5y3kzps5nfnfnik27gdgemfn27iblcjh5bpkio6sr375bmxbh6fshbo7cvjzsdsirsafnbjzgl6ycqczwbacj5sxwgrzl6qbdhfbzev5fzutznzbasejqdjm3qxsdcuqvqau3kih2anr2itgmr44wmwtsk6bd42m2j436ptslaugmbbvtbzsukeqytkse7niovlilyfssn3ipzkqtclmetqrxxn7h56xn2ju7pjnuamd6ijfawn2jpjsrmnawaozeniosvhgovftoj24dl77ytdkxdl7ogappnlgkqsjyy43urtnj6tqf2psfptkbzyx4nu3rzgsqqi5ybx3pu6cvt6de67xutdz566wrkp2ymy5n7tqchmw77ss532noqcbfxv6quum6jmeed3exasdapvid6bilwzm5dcnutkcxktmsdryqopw5ntws3tnbd7um27clmxkgl2uinwzvv4tmo4axbj5zmgfd6sy2fiw6efdwjcyj4awdx3peuxcyh3ccee63w2nqaltierdrevl3f3hnjsrdrl4aosd23szhhaimhg2mjuocottcdsraoczh3waoyxx2skunaphe6w5gutu2z7cag3cx4pgsspfmspphuunzx357x6l36hj3tdys727rhawfwc4wc4ytgts4nrxlxl3xxzffunlhjhzj5guxljwxfrxwjfsg5c67pg3js7gvfqmpson6rjgiuwbsklranwhauq74lbesavftdzf7y3x5zwbi4uu6q2vqimbkttm7k6ycttsgknej2ylkwdxgtut7wecpepnb527pblj3vuzldjt3whsmstax536plulalxtxmvj6vvg4phofyaidhxhhkl4dfb6oabp3fi55jt77pw3jl55pwbsimjpdanuenll2xxctr6swaimuaqk4wvqa6rbgow3onr74v4alkuukc2tlmorvsjpgaazpun6pbfyorazzarhc2r7fjt55pmosowrqcpdwl2q34hcco2f3icmpktchxdvtpmitufnplqaifbtlktkpo7b22244n6dkmxtgcnxtixsit57uhh7rc5rqezjz7pfd7ojhrui5bcdzb7bo2nbo6o24lpwbg4bmqgbqpbwclq6kglgxefryxlkqydillki3545vcrelfw6reszml6emuyjscx377on2qpq26j5jrh5xmbwmpcyq6sewanlbmwwk2vqhq5zunbcyd6h5z3ms3bgfn7lflvev5vwmjnv5nzbgrmpamy453zuvy6xc6jp7tqgpmrlxup7suptejbacm6rdurdhcaori6i25wylgaikfov4dfgeswxdeerogy2m5tbzsdlr7pfhchd4wnokuipfwjzejxiruj5cljm66hvn47j3eseys3nsi6xdh566jgap5s5e7ytdkkhh5lsuv47oose4luozz427dzk577jccjg3n7b4myd565edmsywol3hgh2i54lcya6saaaaaaa"),
|
8: base32.a2b(b"krqwq33febwxk5dbmjwgkiddn5xhiyljnzsxeidwgefhkckeaohm5tnwcmfsfmep4exoamss5lqyleq2ehahoduym5vgk37pmxx2xekzrtlzfvhapzb2fe3quv6tv3atr3g6ykqaaaaaaaaabb5aaaaaaaaaacsoaaaaaakjl2ynvx5mk74p2on26ax4rlp5jcoto5jkz3ndmgbmurhez4a5rbuyr55acbwlgbndlebsdyvlt4ttog767zqpoq3n2a4pra5va2o5zvbttlh45tnwcmfsfmep4exoamss5lqyleq2ehaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarybcjqw7lbehfrbu7pwx26vvv3mbjprnqup7q7wxmdsoyiqaqzgbtv6cplrrgpzbnptsoqz7imnauamfaaaaaaaaaaamgaaaaaaaaaaaymaaaaghqaaacr4aaaayxaaaagnyaaaaaaaaaao4qaaaaaaaaacd2gcbacibqbudaskugjcdpodibaeaqkaadqiaq2abqqiaqqaucaeaqbvkghg3s5ivqiq4uiajdzagl7iqhz2uxwj6aqk47oscyqxyljmxkapldxhxigum2ejxflnps3yrxwwehop2zairilrouid5s6wxgnoqg2vq7rx77icxfnx7mq65niuknra3tezhpndwo7pdxtvtci645p4umyhdh5gp3kbdpypphvouaql662r6ufigp4wwm6emrsavlontn4wttg6lv7bcmq6ojw5utpvz3agoenovrkndncjzxog7sp2w7l6jkmzgfxd2asxos5khkjbxbuhgkd6j5yqlzsmk3kq67engtlgyd7hxk7nedw73bq2bs4353wtler23poucntgve22acfxdbyj2f6q2saj2agu2ptfk364d3zayddffxkcah4olnkczjonselwwrvdcu3vch3licaeirogosgsui3y4ovcyzleurbiunp7fsfk2fgmiek7b3jogvrhj4snvkpqjfh2w2lqnkvqvuoojmgrn6sll354mpomajbtlsv6fuguzgsxsm3l2ehxdxfdv6kcoyogaa5raetooahunf4ltvfdb4d7mwgpj4pg7tmcw55ku5vgx7tjqkdkuyq2uvhavkbsbujsrcfzve5ekuhftxm7nmtomibrblbwyxcr5mcy6qqwx66lrhejmgewrig74nzpriualhw4g22qaw423qeezqn6irea3vlgc3foz4egf6irincownoq7utv643vmtoueebigwrl6nehbos3ipsdx44tmucpvyui2jzgfulb5mrrcjuycmuzfigu6tf25lbysqn7n7smhqniddgctjt573rtd6o63wiaabduzspufh6gomrp7sycuerhgl7ah3x3mpc6watmzlp6y23afmlxcaabui4znebv66jxcst6andsd2tncn4xcb6by7hrbx2ihw45fgzsptiiaaybvqu3gmlomi3dnf2tum3hoseavpesyia2i2wqgwbmbtrgmotu6oaamprqe6ozjrouoeltzhezhntop7wb6bbnnr3ak6x3ihvsjlz77gffkdet4sc63bxykwaikdyxwoehbrggxdu6qcwquzsnaltcgn52nyy4ypqbthfg4txtnznap6dktqtgtmtu7icooojppbwyi5c22uehbveptbuhbi7q3d4wuvsrptnd6wrhxwtlkxe4kurp4fey52p2v6urgephzxmaqfhm7pq3wxbi2uj5ourg65xnhbo4lrp7nzrdmk3svespmmitccvtwom6wtqefpp73j67zybiu4wrjjqt7vhip4ipuaezkmdy7feothks6df52kvobtcnscytmjrrfbekvwmhtbcke2cgcyaj2cra7xmnd4bw2xe2qki5kycopo45ekfyxwzsmxuyxvjzqklnqjwm3j3gwcm75ftnrsvbj33w6eyr4dbz2tewum7vfsyfbb3ojw5ujtn22jxpr4nkmkqup6z7ukpp4cdxwyge2psc5suaxaltmp23gbawoo3qjeo44hgwgtkge2oowox3fpxwxkckaqgrxilfeyxmjp4cwf2rhpkbwtveqkukchv3u5rfkykwfj5zhleu3obsif6ldfclaef32wjpe5d6ddh2grdx2yt6tuhw53t6zuuumlw6t6i3e2ev7nh36e4shwbn3ew2bbahn6imgb5sismfttf5cdlr5kw6wvjoaqiaiz2onxecfx735dvon7epthnklq67tnqj4fvcwechbvmnkpiwd5fd36dirpshc7i7zj3rcr5y3kzps5nfnfnik27gdgemfn27iblcjh5bpkio6sr375bmxbh6fshbo7cvjzsdsirsafnbjzgl6ycqczwbacj5sxwgrzl6qbdhfbzev5fzutznzbasejqdjm3qxsdcuqvqau3kih2anr2itgmr44wmwtsk6bd42m2j436ptslaugmbbvtbzsukeqytkse7niovlilyfssn3ipzkqtclmetqrxxn7h56xn2ju7pjnuamd6ijfawn2jpjsrmnawaozeniosvhgovftoj24dl77ytdkxdl7ogappnlgkqsjyy43urtnj6tqf2psfptkbzyx4nu3rzgsqqi5ybx3pu6cvt6de67xutdz566wrkp2ymy5n7tqchmw77ss532noqcbfxv6quum6jmeed3exasdapvid6bilwzm5dcnutkcxktmsdryqopw5ntws3tnbd7um27clmxkgl2uinwzvv4tmo4axbj5zmgfd6sy2fiw6efdwjcyj4awdx3peuxcyh3ccee63w2nqaltierdrevl3f3hnjsrdrl4aosd23szhhaimhg2mjuocottcdsraoczh3waoyxx2skunaphe6w5gutu2z7cag3cx4pgsspfmspphuunzx357x6l36hj3tdys727rhawfwc4wc4ytgts4nrxlxl3xxzffunlhjhzj5guxljwxfrxwjfsg5c67pg3js7gvfqmpson6rjgiuwbsklranwhauq74lbesavftdzf7y3x5zwbi4uu6q2vqimbkttm7k6ycttsgknej2ylkwdxgtut7wecpepnb527pblj3vuzldjt3whsmstax536plulalxtxmvj6vvg4phofyaidhxhhkl4dfb6oabp3fi55jt77pw3jl55pwbsimjpdanuenll2xxctr6swaimuaqk4wvqa6rbgow3onr74v4alkuukc2tlmorvsjpgaazpun6pbfyorazzarhc2r7fjt55pmosowrqcpdwl2q34hcco2f3icmpktchxdvtpmitufnplqaifbtlktkpo7b22244n6dkmxtgcnxtixsit57uhh7rc5rqezjz7pfd7ojhrui5bcdzb7bo2nbo6o24lpwbg4bmqgbqpbwclq6kglgxefryxlkqydillki3545vcrelfw6reszml6emuyjscx377on2qpq26j5jrh5xmbwmpcyq6sewanlbmwwk2vqhq5zunbcyd6h5z3ms3bgfn7lflvev5vwmjnv5nzbgrmpamy453zuvy6xc6jp7tqgpmrlxup7suptejbacm6rdurdhcaori6i25wylgaikfov4dfgeswxdeerogy2m5tbzsdlr7pfhchd4wnokuipfwjzejxiruj5cljm66hvn47j3eseys3nsi6xdh566jgap5s5e7ytdkkhh5lsuv47oose4luozz427dzk577jccjg3n7b4myd565edmsywol3hgh2i54lcya6saaaaaaa"),
|
||||||
},
|
},
|
||||||
2: { # client[2]
|
2: { # client[2]
|
||||||
4: base32.a2b("krqwq33febwxk5dbmjwgkiddn5xhiyljnzsxeidwgefhkckeaohelfyqrvy7pzjh3tqx73xsfkpi3so4qjghlywdkwuioyjvbtgekiulaes4myuxydi2sudi2fkg2q5nkjrt3zaaaaaaaaaabb5aaaaaaaaaacsoaaaaaakjl2ynujj2kh34jfiungka3deihevw7p3mzhj7uobc3qnbfxqp3xfazrsicvtz3enqkn4xxlu5xvxjj2rtlv6j3w3kmpzn2jbrnuoafq2aacoulfyqrvy7pzjh3tqx73xsfkpi3so4qjgaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarybcjqw7lbehfrbu7pwx26vvv3mbjprnqup7q7wxmdsoyiqaqzgbtv6cplrrgpzbnptsoqz7imnauamfaaaaaaaaaaamgaaaaaaaaaaaymaaaaghqaaacr4aaaayxaaaagnyaaaaaaaaaao4qaaaaaaaaacd2gcbacibqbudaskugjcdpodibaeaqkaadqiaq2abqqiaqqaucaeaqbvkghg3s5ivqiq4uiajdzagl7iqhz2uxwj6aqk47oscyqxyljmxkapldxhxigum2ejxflnps3yrxwwehop2zairilrouid5s6wxgnoqg2vq7rx77icxfnx7mq65niuknra3tezhpndwo7pdxtvtci645p4umyhdh5gp3kbdpypphvouaql662r6ufigp4wwm6emrsavlontn4wttg6lv7bcmq6ojw5utpvz3agoenovrkndncjzxog7sp2w7l6jkmzgfxd2asxos5khkjbxbuhgkd6j5yqlzsmk3kq67engtlgyd7hxk7nedw73bq2bs4353wtler23poucntgve22acfxdbyj2f6q2saj2agu2ptfk364d3zayddffxkcah4olnkczjonselwwrvdcu3vch3licaeirogosgsui3y4ovcyzleurbiunp7fsfk2fgmiek7b3jogvrhj4snvkpqjfh2w2lqnkvqvuoojmgrn6sll354mpomajbtlsv6fuguzgsxsm3l2ehxdxfdv6kcoyogaa5raetooahunf4ltvfdb4d7mwgpj4pg7tmcw55ku5vgx7tjqkdkuyq2uvhavkbsbujsrcfzve5ekuhftxm7nmtomibrblbwyxcr5mcy6qqwx66lrhejmgewrig74nzpriualhw4g22qaw423qeezqn6irea3vlgc3foz4egf6irincownoq7utv643vmtoueebigwrl6nehbos3ipsdx44tmucpvyui2jzgfulb5mrrcjuycmuzfigu6tf25lbysqn7n7smhqniddgctjt573rtd6o63wiaactacm7dw7giohzcgwe4okbijnmzlacetmfjjbasrd6whexjmwkaiaaazuum3xriq54h5v6afcrrl3kkbd46oizwulc5fbslmblxfc3ldyyqaavmjy6g336aewy42vw5rusytyi7vzs6y22c5jhxyt5w6gthcbjp4zaakhlvz26psskxjisz27qlpzw4annhegunhnvlyr35ijotdizegjf4lgx3o4dt3d6d4bjqexz2eu3dprjlmuvlkbfcpmkq2ceydywqqcqdhmdl2nm5ku6z6gnss2bsbn7ycab2ggktr3bjlzaeo5pb4meolrckviwiddsikieo4wyatlxtybmzkoh3fb2vxc34xb47ty2cyi55xjan6m4bbie7muzrzmjmzviwlotk6icove7ydpag6dlrjwu4svgs3y2ln5r463dmflqs3p4aa7dldhjb5kfpxq63tgquunkucsfvlkaiiisgthks6df52kvobtcnscytmjrrfbekvwmhtbcke2cgcyaj2cra7xmnd4bw2xe2qki5kycopo45ekfyxwzsmxuyxvjzqklnqjwm3j3gwcm75ftnrsvbj33w6eyr4dbz2tewum7vfsyfbb3ojw5ujtn22jxpr4nkmkqup6z7ukpp4cdxwyge2psc5suaxaltmp23gbawoo3qjeo44hgwgtkge2oowox3fpxwxkckaqgrxilfeyxmjp4cwf2rhpkbwtveqkukchv3u5rfkykwfj5zhleu3obsif6ldfclaef32wjpe5d6ddh2grdx2yt6tuhw53t6zuuumlw6t6i3e2ev7nh36e4shwbn3ew2bbahn6imgb5sismfttf5cdlr5kw6wvjoaqiaiz2onxecfx735dvon7epthnklq67tnqj4fvcwechbvmnkpiwd5fd36dirpshc7i7zj3rcr5y3kzps5nfnfnik27gdgemfn27iblcjh5bpkio6sr375bmxbh6fshbo7cvjzsdsirsafnbjzgl6ycqczwbacj5sxwgrzl6qbdhfbzev5fzutznzbasejqdjm3qxsdcuqvqau3kih2anr2itgmr44wmwtsk6bd42m2j436ptslaugmbbvtbzsukeqytkse7niovlilyfssn3ipzkqtclmetqrxxn7h56xn2ju7pjnuamd6ijfawn2jpjsrmnawaozeniosvhgovftoj24dl77ytdkxdl7ogappnlgkqsjyy43urtnj6tqf2psfptkbzyx4nu3rzgsqqi5ybx3pu6cvt6de67xutdz566wrkp2ymy5n7tqchmw77ss532noqcbfxv6quum6jmeed3exasdapvid6bilwzm5dcnutkcxktmsdryqopw5ntws3tnbd7um27clmxkgl2uinwzvv4tmo4axbj5zmgfd6sy2fiw6efdwjcyj4awdx3peuxcyh3ccee63w2nqaltierdrevl3f3hnjsrdrl4aosd23szhhaimhg2mjuocottcdsraoczh3waoyxx2skunaphe6w5gutu2z7cag3cx4pgsspfmspphuunzx357x6l36hj3tdys727rhawfwc4wc4ytgts4nrxlxl3xxzffunlhjhzj5guxljwxfrxwjfsg5c67pg3js7gvfqmpson6rjgiuwbsklranwhauq74lbesavftdzf7y3x5zwbi4uu6q2vqimbkttm7k6ycttsgknej2ylkwdxgtut7wecpepnb527pblj3vuzldjt3whsmstax536plulalxtxmvj6vvg4phofyaidhxhhkl4dfb6oabp3fi55jt77pw3jl55pwbsimjpdanuenll2xxctr6swaimuaqk4wvqa6rbgow3onr74v4alkuukc2tlmorvsjpgaazpun6pbfyorazzarhc2r7fjt55pmosowrqcpdwl2q34hcco2f3icmpktchxdvtpmitufnplqaifbtlktkpo7b22244n6dkmxtgcnxtixsit57uhh7rc5rqezjz7pfd7ojhrui5bcdzb7bo2nbo6o24lpwbg4bmqgbqpbwclq6kglgxefryxlkqydillki3545vcrelfw6reszml6emuyjscx377on2qpq26j5jrh5xmbwmpcyq6sewanlbmwwk2vqhq5zunbcyd6h5z3ms3bgfn7lflvev5vwmjnv5nzbgrmpamy453zuvy6xc6jp7tqgpmrlxup7suptejbacm6rdurdhcaori6i25wylgaikfov4dfgeswxdeerogy2m5tbzsdlr7pfhchd4wnokuipfwjzejxiruj5cljm66hvn47j3eseys3nsi6xdh566jgap5s5e7ytdkkhh5lsuv47oose4luozz427dzk577jccjg3n7b4myd565edmsywol3hgh2i54lcya6saaaaaaa"),
|
4: base32.a2b(b"krqwq33febwxk5dbmjwgkiddn5xhiyljnzsxeidwgefhkckeaohelfyqrvy7pzjh3tqx73xsfkpi3so4qjghlywdkwuioyjvbtgekiulaes4myuxydi2sudi2fkg2q5nkjrt3zaaaaaaaaaabb5aaaaaaaaaacsoaaaaaakjl2ynujj2kh34jfiungka3deihevw7p3mzhj7uobc3qnbfxqp3xfazrsicvtz3enqkn4xxlu5xvxjj2rtlv6j3w3kmpzn2jbrnuoafq2aacoulfyqrvy7pzjh3tqx73xsfkpi3so4qjgaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarybcjqw7lbehfrbu7pwx26vvv3mbjprnqup7q7wxmdsoyiqaqzgbtv6cplrrgpzbnptsoqz7imnauamfaaaaaaaaaaamgaaaaaaaaaaaymaaaaghqaaacr4aaaayxaaaagnyaaaaaaaaaao4qaaaaaaaaacd2gcbacibqbudaskugjcdpodibaeaqkaadqiaq2abqqiaqqaucaeaqbvkghg3s5ivqiq4uiajdzagl7iqhz2uxwj6aqk47oscyqxyljmxkapldxhxigum2ejxflnps3yrxwwehop2zairilrouid5s6wxgnoqg2vq7rx77icxfnx7mq65niuknra3tezhpndwo7pdxtvtci645p4umyhdh5gp3kbdpypphvouaql662r6ufigp4wwm6emrsavlontn4wttg6lv7bcmq6ojw5utpvz3agoenovrkndncjzxog7sp2w7l6jkmzgfxd2asxos5khkjbxbuhgkd6j5yqlzsmk3kq67engtlgyd7hxk7nedw73bq2bs4353wtler23poucntgve22acfxdbyj2f6q2saj2agu2ptfk364d3zayddffxkcah4olnkczjonselwwrvdcu3vch3licaeirogosgsui3y4ovcyzleurbiunp7fsfk2fgmiek7b3jogvrhj4snvkpqjfh2w2lqnkvqvuoojmgrn6sll354mpomajbtlsv6fuguzgsxsm3l2ehxdxfdv6kcoyogaa5raetooahunf4ltvfdb4d7mwgpj4pg7tmcw55ku5vgx7tjqkdkuyq2uvhavkbsbujsrcfzve5ekuhftxm7nmtomibrblbwyxcr5mcy6qqwx66lrhejmgewrig74nzpriualhw4g22qaw423qeezqn6irea3vlgc3foz4egf6irincownoq7utv643vmtoueebigwrl6nehbos3ipsdx44tmucpvyui2jzgfulb5mrrcjuycmuzfigu6tf25lbysqn7n7smhqniddgctjt573rtd6o63wiaactacm7dw7giohzcgwe4okbijnmzlacetmfjjbasrd6whexjmwkaiaaazuum3xriq54h5v6afcrrl3kkbd46oizwulc5fbslmblxfc3ldyyqaavmjy6g336aewy42vw5rusytyi7vzs6y22c5jhxyt5w6gthcbjp4zaakhlvz26psskxjisz27qlpzw4annhegunhnvlyr35ijotdizegjf4lgx3o4dt3d6d4bjqexz2eu3dprjlmuvlkbfcpmkq2ceydywqqcqdhmdl2nm5ku6z6gnss2bsbn7ycab2ggktr3bjlzaeo5pb4meolrckviwiddsikieo4wyatlxtybmzkoh3fb2vxc34xb47ty2cyi55xjan6m4bbie7muzrzmjmzviwlotk6icove7ydpag6dlrjwu4svgs3y2ln5r463dmflqs3p4aa7dldhjb5kfpxq63tgquunkucsfvlkaiiisgthks6df52kvobtcnscytmjrrfbekvwmhtbcke2cgcyaj2cra7xmnd4bw2xe2qki5kycopo45ekfyxwzsmxuyxvjzqklnqjwm3j3gwcm75ftnrsvbj33w6eyr4dbz2tewum7vfsyfbb3ojw5ujtn22jxpr4nkmkqup6z7ukpp4cdxwyge2psc5suaxaltmp23gbawoo3qjeo44hgwgtkge2oowox3fpxwxkckaqgrxilfeyxmjp4cwf2rhpkbwtveqkukchv3u5rfkykwfj5zhleu3obsif6ldfclaef32wjpe5d6ddh2grdx2yt6tuhw53t6zuuumlw6t6i3e2ev7nh36e4shwbn3ew2bbahn6imgb5sismfttf5cdlr5kw6wvjoaqiaiz2onxecfx735dvon7epthnklq67tnqj4fvcwechbvmnkpiwd5fd36dirpshc7i7zj3rcr5y3kzps5nfnfnik27gdgemfn27iblcjh5bpkio6sr375bmxbh6fshbo7cvjzsdsirsafnbjzgl6ycqczwbacj5sxwgrzl6qbdhfbzev5fzutznzbasejqdjm3qxsdcuqvqau3kih2anr2itgmr44wmwtsk6bd42m2j436ptslaugmbbvtbzsukeqytkse7niovlilyfssn3ipzkqtclmetqrxxn7h56xn2ju7pjnuamd6ijfawn2jpjsrmnawaozeniosvhgovftoj24dl77ytdkxdl7ogappnlgkqsjyy43urtnj6tqf2psfptkbzyx4nu3rzgsqqi5ybx3pu6cvt6de67xutdz566wrkp2ymy5n7tqchmw77ss532noqcbfxv6quum6jmeed3exasdapvid6bilwzm5dcnutkcxktmsdryqopw5ntws3tnbd7um27clmxkgl2uinwzvv4tmo4axbj5zmgfd6sy2fiw6efdwjcyj4awdx3peuxcyh3ccee63w2nqaltierdrevl3f3hnjsrdrl4aosd23szhhaimhg2mjuocottcdsraoczh3waoyxx2skunaphe6w5gutu2z7cag3cx4pgsspfmspphuunzx357x6l36hj3tdys727rhawfwc4wc4ytgts4nrxlxl3xxzffunlhjhzj5guxljwxfrxwjfsg5c67pg3js7gvfqmpson6rjgiuwbsklranwhauq74lbesavftdzf7y3x5zwbi4uu6q2vqimbkttm7k6ycttsgknej2ylkwdxgtut7wecpepnb527pblj3vuzldjt3whsmstax536plulalxtxmvj6vvg4phofyaidhxhhkl4dfb6oabp3fi55jt77pw3jl55pwbsimjpdanuenll2xxctr6swaimuaqk4wvqa6rbgow3onr74v4alkuukc2tlmorvsjpgaazpun6pbfyorazzarhc2r7fjt55pmosowrqcpdwl2q34hcco2f3icmpktchxdvtpmitufnplqaifbtlktkpo7b22244n6dkmxtgcnxtixsit57uhh7rc5rqezjz7pfd7ojhrui5bcdzb7bo2nbo6o24lpwbg4bmqgbqpbwclq6kglgxefryxlkqydillki3545vcrelfw6reszml6emuyjscx377on2qpq26j5jrh5xmbwmpcyq6sewanlbmwwk2vqhq5zunbcyd6h5z3ms3bgfn7lflvev5vwmjnv5nzbgrmpamy453zuvy6xc6jp7tqgpmrlxup7suptejbacm6rdurdhcaori6i25wylgaikfov4dfgeswxdeerogy2m5tbzsdlr7pfhchd4wnokuipfwjzejxiruj5cljm66hvn47j3eseys3nsi6xdh566jgap5s5e7ytdkkhh5lsuv47oose4luozz427dzk577jccjg3n7b4myd565edmsywol3hgh2i54lcya6saaaaaaa"),
|
||||||
9: base32.a2b("krqwq33febwxk5dbmjwgkiddn5xhiyljnzsxeidwgefhkckeaohelfyqrvy7pzjh3tqx73xsfkpi3so4qjghlywdkwuioyjvbtgekiulaes4myuxydi2sudi2fkg2q5nkjrt3zaaaaaaaaaabb5aaaaaaaaaacsoaaaaaakjl2ynujj2kh34jfiungka3deihevw7p3mzhj7uobc3qnbfxqp3xfazrsicvtz3enqkn4xxlu5xvxjj2rtlv6j3w3kmpzn2jbrnuoafq2aacoulfyqrvy7pzjh3tqx73xsfkpi3so4qjgaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarybcjqw7lbehfrbu7pwx26vvv3mbjprnqup7q7wxmdsoyiqaqzgbtv6cplrrgpzbnptsoqz7imnauamfaaaaaaaaaaamgaaaaaaaaaaaymaaaaghqaaacr4aaaayxaaaagnyaaaaaaaaaao4qaaaaaaaaacd2gcbacibqbudaskugjcdpodibaeaqkaadqiaq2abqqiaqqaucaeaqbvkghg3s5ivqiq4uiajdzagl7iqhz2uxwj6aqk47oscyqxyljmxkapldxhxigum2ejxflnps3yrxwwehop2zairilrouid5s6wxgnoqg2vq7rx77icxfnx7mq65niuknra3tezhpndwo7pdxtvtci645p4umyhdh5gp3kbdpypphvouaql662r6ufigp4wwm6emrsavlontn4wttg6lv7bcmq6ojw5utpvz3agoenovrkndncjzxog7sp2w7l6jkmzgfxd2asxos5khkjbxbuhgkd6j5yqlzsmk3kq67engtlgyd7hxk7nedw73bq2bs4353wtler23poucntgve22acfxdbyj2f6q2saj2agu2ptfk364d3zayddffxkcah4olnkczjonselwwrvdcu3vch3licaeirogosgsui3y4ovcyzleurbiunp7fsfk2fgmiek7b3jogvrhj4snvkpqjfh2w2lqnkvqvuoojmgrn6sll354mpomajbtlsv6fuguzgsxsm3l2ehxdxfdv6kcoyogaa5raetooahunf4ltvfdb4d7mwgpj4pg7tmcw55ku5vgx7tjqkdkuyq2uvhavkbsbujsrcfzve5ekuhftxm7nmtomibrblbwyxcr5mcy6qqwx66lrhejmgewrig74nzpriualhw4g22qaw423qeezqn6irea3vlgc3foz4egf6irincownoq7utv643vmtoueebigwrl6nehbos3ipsdx44tmucpvyui2jzgfulb5mrrcjuycmuzfigu6tf25lbysqn7n7smhqniddgctjt573rtd6o63wiaabduzspufh6gomrp7sycuerhgl7ah3x3mpc6watmzlp6y23afmlxcaabui4znebv66jxcst6andsd2tncn4xcb6by7hrbx2ihw45fgzsptiiaaybvqu3gmlomi3dnf2tum3hoseavpesyia2i2wqgwbmbtrgmotu6oaalugjhzef5wdpqvmaquhrpm4iodcmnohj5afnbjte2axgem33u3rr7yycphmuyxkhcfz4tsmtwzxh73a7aqwwy5qfpl5ud2zev477tcsviylwmlv6fgp54rk4iwputjkcgegczq6uynbvebu67jf6f2foocphznw7jrdsvphppguypjwmkkhugm6yjnrjka2ycvxsyh5xohn3fvbbhl4tvhedbaix3zlwxeayabnldp3oqnkjger7yrxh44wuv3adb76jh3nl6h45t4ixj77himst5plmpdtexyoozpxzjmedge5leynxhziothks6df52kvobtcnscytmjrrfbekvwmhtbcke2cgcyaj2cra7xmnd4bw2xe2qki5kycopo45ekfyxwzsmxuyxvjzqklnqjwm3j3gwcm75ftnrsvbj33w6eyr4dbz2tewum7vfsyfbb3ojw5ujtn22jxpr4nkmkqup6z7ukpp4cdxwyge2psc5suaxaltmp23gbawoo3qjeo44hgwgtkge2oowox3fpxwxkckaqgrxilfeyxmjp4cwf2rhpkbwtveqkukchv3u5rfkykwfj5zhleu3obsif6ldfclaef32wjpe5d6ddh2grdx2yt6tuhw53t6zuuumlw6t6i3e2ev7nh36e4shwbn3ew2bbahn6imgb5sismfttf5cdlr5kw6wvjoaqiaiz2onxecfx735dvon7epthnklq67tnqj4fvcwechbvmnkpiwd5fd36dirpshc7i7zj3rcr5y3kzps5nfnfnik27gdgemfn27iblcjh5bpkio6sr375bmxbh6fshbo7cvjzsdsirsafnbjzgl6ycqczwbacj5sxwgrzl6qbdhfbzev5fzutznzbasejqdjm3qxsdcuqvqau3kih2anr2itgmr44wmwtsk6bd42m2j436ptslaugmbbvtbzsukeqytkse7niovlilyfssn3ipzkqtclmetqrxxn7h56xn2ju7pjnuamd6ijfawn2jpjsrmnawaozeniosvhgovftoj24dl77ytdkxdl7ogappnlgkqsjyy43urtnj6tqf2psfptkbzyx4nu3rzgsqqi5ybx3pu6cvt6de67xutdz566wrkp2ymy5n7tqchmw77ss532noqcbfxv6quum6jmeed3exasdapvid6bilwzm5dcnutkcxktmsdryqopw5ntws3tnbd7um27clmxkgl2uinwzvv4tmo4axbj5zmgfd6sy2fiw6efdwjcyj4awdx3peuxcyh3ccee63w2nqaltierdrevl3f3hnjsrdrl4aosd23szhhaimhg2mjuocottcdsraoczh3waoyxx2skunaphe6w5gutu2z7cag3cx4pgsspfmspphuunzx357x6l36hj3tdys727rhawfwc4wc4ytgts4nrxlxl3xxzffunlhjhzj5guxljwxfrxwjfsg5c67pg3js7gvfqmpson6rjgiuwbsklranwhauq74lbesavftdzf7y3x5zwbi4uu6q2vqimbkttm7k6ycttsgknej2ylkwdxgtut7wecpepnb527pblj3vuzldjt3whsmstax536plulalxtxmvj6vvg4phofyaidhxhhkl4dfb6oabp3fi55jt77pw3jl55pwbsimjpdanuenll2xxctr6swaimuaqk4wvqa6rbgow3onr74v4alkuukc2tlmorvsjpgaazpun6pbfyorazzarhc2r7fjt55pmosowrqcpdwl2q34hcco2f3icmpktchxdvtpmitufnplqaifbtlktkpo7b22244n6dkmxtgcnxtixsit57uhh7rc5rqezjz7pfd7ojhrui5bcdzb7bo2nbo6o24lpwbg4bmqgbqpbwclq6kglgxefryxlkqydillki3545vcrelfw6reszml6emuyjscx377on2qpq26j5jrh5xmbwmpcyq6sewanlbmwwk2vqhq5zunbcyd6h5z3ms3bgfn7lflvev5vwmjnv5nzbgrmpamy453zuvy6xc6jp7tqgpmrlxup7suptejbacm6rdurdhcaori6i25wylgaikfov4dfgeswxdeerogy2m5tbzsdlr7pfhchd4wnokuipfwjzejxiruj5cljm66hvn47j3eseys3nsi6xdh566jgap5s5e7ytdkkhh5lsuv47oose4luozz427dzk577jccjg3n7b4myd565edmsywol3hgh2i54lcya6saaaaaaa"),
|
9: base32.a2b(b"krqwq33febwxk5dbmjwgkiddn5xhiyljnzsxeidwgefhkckeaohelfyqrvy7pzjh3tqx73xsfkpi3so4qjghlywdkwuioyjvbtgekiulaes4myuxydi2sudi2fkg2q5nkjrt3zaaaaaaaaaabb5aaaaaaaaaacsoaaaaaakjl2ynujj2kh34jfiungka3deihevw7p3mzhj7uobc3qnbfxqp3xfazrsicvtz3enqkn4xxlu5xvxjj2rtlv6j3w3kmpzn2jbrnuoafq2aacoulfyqrvy7pzjh3tqx73xsfkpi3so4qjgaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarybcjqw7lbehfrbu7pwx26vvv3mbjprnqup7q7wxmdsoyiqaqzgbtv6cplrrgpzbnptsoqz7imnauamfaaaaaaaaaaamgaaaaaaaaaaaymaaaaghqaaacr4aaaayxaaaagnyaaaaaaaaaao4qaaaaaaaaacd2gcbacibqbudaskugjcdpodibaeaqkaadqiaq2abqqiaqqaucaeaqbvkghg3s5ivqiq4uiajdzagl7iqhz2uxwj6aqk47oscyqxyljmxkapldxhxigum2ejxflnps3yrxwwehop2zairilrouid5s6wxgnoqg2vq7rx77icxfnx7mq65niuknra3tezhpndwo7pdxtvtci645p4umyhdh5gp3kbdpypphvouaql662r6ufigp4wwm6emrsavlontn4wttg6lv7bcmq6ojw5utpvz3agoenovrkndncjzxog7sp2w7l6jkmzgfxd2asxos5khkjbxbuhgkd6j5yqlzsmk3kq67engtlgyd7hxk7nedw73bq2bs4353wtler23poucntgve22acfxdbyj2f6q2saj2agu2ptfk364d3zayddffxkcah4olnkczjonselwwrvdcu3vch3licaeirogosgsui3y4ovcyzleurbiunp7fsfk2fgmiek7b3jogvrhj4snvkpqjfh2w2lqnkvqvuoojmgrn6sll354mpomajbtlsv6fuguzgsxsm3l2ehxdxfdv6kcoyogaa5raetooahunf4ltvfdb4d7mwgpj4pg7tmcw55ku5vgx7tjqkdkuyq2uvhavkbsbujsrcfzve5ekuhftxm7nmtomibrblbwyxcr5mcy6qqwx66lrhejmgewrig74nzpriualhw4g22qaw423qeezqn6irea3vlgc3foz4egf6irincownoq7utv643vmtoueebigwrl6nehbos3ipsdx44tmucpvyui2jzgfulb5mrrcjuycmuzfigu6tf25lbysqn7n7smhqniddgctjt573rtd6o63wiaabduzspufh6gomrp7sycuerhgl7ah3x3mpc6watmzlp6y23afmlxcaabui4znebv66jxcst6andsd2tncn4xcb6by7hrbx2ihw45fgzsptiiaaybvqu3gmlomi3dnf2tum3hoseavpesyia2i2wqgwbmbtrgmotu6oaalugjhzef5wdpqvmaquhrpm4iodcmnohj5afnbjte2axgem33u3rr7yycphmuyxkhcfz4tsmtwzxh73a7aqwwy5qfpl5ud2zev477tcsviylwmlv6fgp54rk4iwputjkcgegczq6uynbvebu67jf6f2foocphznw7jrdsvphppguypjwmkkhugm6yjnrjka2ycvxsyh5xohn3fvbbhl4tvhedbaix3zlwxeayabnldp3oqnkjger7yrxh44wuv3adb76jh3nl6h45t4ixj77himst5plmpdtexyoozpxzjmedge5leynxhziothks6df52kvobtcnscytmjrrfbekvwmhtbcke2cgcyaj2cra7xmnd4bw2xe2qki5kycopo45ekfyxwzsmxuyxvjzqklnqjwm3j3gwcm75ftnrsvbj33w6eyr4dbz2tewum7vfsyfbb3ojw5ujtn22jxpr4nkmkqup6z7ukpp4cdxwyge2psc5suaxaltmp23gbawoo3qjeo44hgwgtkge2oowox3fpxwxkckaqgrxilfeyxmjp4cwf2rhpkbwtveqkukchv3u5rfkykwfj5zhleu3obsif6ldfclaef32wjpe5d6ddh2grdx2yt6tuhw53t6zuuumlw6t6i3e2ev7nh36e4shwbn3ew2bbahn6imgb5sismfttf5cdlr5kw6wvjoaqiaiz2onxecfx735dvon7epthnklq67tnqj4fvcwechbvmnkpiwd5fd36dirpshc7i7zj3rcr5y3kzps5nfnfnik27gdgemfn27iblcjh5bpkio6sr375bmxbh6fshbo7cvjzsdsirsafnbjzgl6ycqczwbacj5sxwgrzl6qbdhfbzev5fzutznzbasejqdjm3qxsdcuqvqau3kih2anr2itgmr44wmwtsk6bd42m2j436ptslaugmbbvtbzsukeqytkse7niovlilyfssn3ipzkqtclmetqrxxn7h56xn2ju7pjnuamd6ijfawn2jpjsrmnawaozeniosvhgovftoj24dl77ytdkxdl7ogappnlgkqsjyy43urtnj6tqf2psfptkbzyx4nu3rzgsqqi5ybx3pu6cvt6de67xutdz566wrkp2ymy5n7tqchmw77ss532noqcbfxv6quum6jmeed3exasdapvid6bilwzm5dcnutkcxktmsdryqopw5ntws3tnbd7um27clmxkgl2uinwzvv4tmo4axbj5zmgfd6sy2fiw6efdwjcyj4awdx3peuxcyh3ccee63w2nqaltierdrevl3f3hnjsrdrl4aosd23szhhaimhg2mjuocottcdsraoczh3waoyxx2skunaphe6w5gutu2z7cag3cx4pgsspfmspphuunzx357x6l36hj3tdys727rhawfwc4wc4ytgts4nrxlxl3xxzffunlhjhzj5guxljwxfrxwjfsg5c67pg3js7gvfqmpson6rjgiuwbsklranwhauq74lbesavftdzf7y3x5zwbi4uu6q2vqimbkttm7k6ycttsgknej2ylkwdxgtut7wecpepnb527pblj3vuzldjt3whsmstax536plulalxtxmvj6vvg4phofyaidhxhhkl4dfb6oabp3fi55jt77pw3jl55pwbsimjpdanuenll2xxctr6swaimuaqk4wvqa6rbgow3onr74v4alkuukc2tlmorvsjpgaazpun6pbfyorazzarhc2r7fjt55pmosowrqcpdwl2q34hcco2f3icmpktchxdvtpmitufnplqaifbtlktkpo7b22244n6dkmxtgcnxtixsit57uhh7rc5rqezjz7pfd7ojhrui5bcdzb7bo2nbo6o24lpwbg4bmqgbqpbwclq6kglgxefryxlkqydillki3545vcrelfw6reszml6emuyjscx377on2qpq26j5jrh5xmbwmpcyq6sewanlbmwwk2vqhq5zunbcyd6h5z3ms3bgfn7lflvev5vwmjnv5nzbgrmpamy453zuvy6xc6jp7tqgpmrlxup7suptejbacm6rdurdhcaori6i25wylgaikfov4dfgeswxdeerogy2m5tbzsdlr7pfhchd4wnokuipfwjzejxiruj5cljm66hvn47j3eseys3nsi6xdh566jgap5s5e7ytdkkhh5lsuv47oose4luozz427dzk577jccjg3n7b4myd565edmsywol3hgh2i54lcya6saaaaaaa"),
|
||||||
},
|
},
|
||||||
3: { # client[3]
|
3: { # client[3]
|
||||||
1: base32.a2b("krqwq33febwxk5dbmjwgkiddn5xhiyljnzsxeidwgefhkckeaohar2c5jzdcrekne6myzpxl2z65d6ufdjuuyhabg2j57ecmy23jyflcp7djzupj4tfr345bkg7cmwxmpmn3h4iaaaaaaaaabb5aaaaaaaaaacsoaaaaaakjl2ynu3sjzjwrfjn4cwfspkueq47j6ej2uodmjsjexyray7dn6ut4nnuftdhhgxo3t3a5eoipsdy5evdihyeigny3c4adtpveplcwt76m7naar2c5jzdcrekne6myzpxl2z65d6ufdjuqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarybcjqw7lbehfrbu7pwx26vvv3mbjprnqup7q7wxmdsoyiqaqzgbtv6cplrrgpzbnptsoqz7imnauamfaaaaaaaaaaamgaaaaaaaaaaaymaaaaghqaaacr4aaaayxaaaagnyaaaaaaaaaao4qaaaaaaaaacd2gcbacibqbudaskugjcdpodibaeaqkaadqiaq2abqqiaqqaucaeaqbvkghg3s5ivqiq4uiajdzagl7iqhz2uxwj6aqk47oscyqxyljmxkapldxhxigum2ejxflnps3yrxwwehop2zairilrouid5s6wxgnoqg2vq7rx77icxfnx7mq65niuknra3tezhpndwo7pdxtvtci645p4umyhdh5gp3kbdpypphvouaql662r6ufigp4wwm6emrsavlontn4wttg6lv7bcmq6ojw5utpvz3agoenovrkndncjzxog7sp2w7l6jkmzgfxd2asxos5khkjbxbuhgkd6j5yqlzsmk3kq67engtlgyd7hxk7nedw73bq2bs4353wtler23poucntgve22acfxdbyj2f6q2saj2agu2ptfk364d3zayddffxkcah4olnkczjonselwwrvdcu3vch3licaeirogosgsui3y4ovcyzleurbiunp7fsfk2fgmiek7b3jogvrhj4snvkpqjfh2w2lqnkvqvuoojmgrn6sll354mpomajbtlsv6fuguzgsxsm3l2ehxdxfdv6kcoyogaa5raetooahunf4ltvfdb4d7mwgpj4pg7tmcw55ku5vgx7tjqkdkuyq2uvhavkbsbujsrcfzve5ekuhftxm7nmtomibrblbwyxcr5mcy6qqwx66lrhejmgewrig74nzpriualhw4g22qaw423qeezqn6irea3vlgc3foz4egf6irincownoq7utv643vmtoueebigwrl6nehbos3ipsdx44tmucpvyui2jzgfulb5mrrcjuycmuzfigu6tf25lbysqn7n7smhqniddgctjt573rtd6o63wiaactacm7dw7giohzcgwe4okbijnmzlacetmfjjbasrd6whexjmwkaiaabdm4cpjolak4m47telnokjaxwodj7ont7n7vffnmhkzp3lyshkh3qaarzybn64ru5rss7tmi4ttv26q66ebdvvrtyd3s5t7dmqku3uoefroaahxhmt46bsa3cpmjfwjyw3zijhhbqh3j2dbc42jaqj6wvmxoz7pecirykndmb6dylde5utzkpucky5pk3x4u6dphkq2ycmfuyvpg5lsudusosyofwfnokbe7qmld2xwaxah3qkywarndsfvp3rybq2y7q42silj5cnlbdxnabv2zhhix3h5o5kz2ttqzm34clnbo527obrxvqlxz3sofwcmz2kqs4c3ypj6o4ny4hkh6qu7ljs7xiygzmoojhnaxc6wjbnvnsu2socztfaegy6ft22tgtdudtok4z755vgj3etwmje73af2f2thks6df52kvobtcnscytmjrrfbekvwmhtbcke2cgcyaj2cra7xmnd4bw2xe2qki5kycopo45ekfyxwzsmxuyxvjzqklnqjwm3j3gwcm75ftnrsvbj33w6eyr4dbz2tewum7vfsyfbb3ojw5ujtn22jxpr4nkmkqup6z7ukpp4cdxwyge2psc5suaxaltmp23gbawoo3qjeo44hgwgtkge2oowox3fpxwxkckaqgrxilfeyxmjp4cwf2rhpkbwtveqkukchv3u5rfkykwfj5zhleu3obsif6ldfclaef32wjpe5d6ddh2grdx2yt6tuhw53t6zuuumlw6t6i3e2ev7nh36e4shwbn3ew2bbahn6imgb5sismfttf5cdlr5kw6wvjoaqiaiz2onxecfx735dvon7epthnklq67tnqj4fvcwechbvmnkpiwd5fd36dirpshc7i7zj3rcr5y3kzps5nfnfnik27gdgemfn27iblcjh5bpkio6sr375bmxbh6fshbo7cvjzsdsirsafnbjzgl6ycqczwbacj5sxwgrzl6qbdhfbzev5fzutznzbasejqdjm3qxsdcuqvqau3kih2anr2itgmr44wmwtsk6bd42m2j436ptslaugmbbvtbzsukeqytkse7niovlilyfssn3ipzkqtclmetqrxxn7h56xn2ju7pjnuamd6ijfawn2jpjsrmnawaozeniosvhgovftoj24dl77ytdkxdl7ogappnlgkqsjyy43urtnj6tqf2psfptkbzyx4nu3rzgsqqi5ybx3pu6cvt6de67xutdz566wrkp2ymy5n7tqchmw77ss532noqcbfxv6quum6jmeed3exasdapvid6bilwzm5dcnutkcxktmsdryqopw5ntws3tnbd7um27clmxkgl2uinwzvv4tmo4axbj5zmgfd6sy2fiw6efdwjcyj4awdx3peuxcyh3ccee63w2nqaltierdrevl3f3hnjsrdrl4aosd23szhhaimhg2mjuocottcdsraoczh3waoyxx2skunaphe6w5gutu2z7cag3cx4pgsspfmspphuunzx357x6l36hj3tdys727rhawfwc4wc4ytgts4nrxlxl3xxzffunlhjhzj5guxljwxfrxwjfsg5c67pg3js7gvfqmpson6rjgiuwbsklranwhauq74lbesavftdzf7y3x5zwbi4uu6q2vqimbkttm7k6ycttsgknej2ylkwdxgtut7wecpepnb527pblj3vuzldjt3whsmstax536plulalxtxmvj6vvg4phofyaidhxhhkl4dfb6oabp3fi55jt77pw3jl55pwbsimjpdanuenll2xxctr6swaimuaqk4wvqa6rbgow3onr74v4alkuukc2tlmorvsjpgaazpun6pbfyorazzarhc2r7fjt55pmosowrqcpdwl2q34hcco2f3icmpktchxdvtpmitufnplqaifbtlktkpo7b22244n6dkmxtgcnxtixsit57uhh7rc5rqezjz7pfd7ojhrui5bcdzb7bo2nbo6o24lpwbg4bmqgbqpbwclq6kglgxefryxlkqydillki3545vcrelfw6reszml6emuyjscx377on2qpq26j5jrh5xmbwmpcyq6sewanlbmwwk2vqhq5zunbcyd6h5z3ms3bgfn7lflvev5vwmjnv5nzbgrmpamy453zuvy6xc6jp7tqgpmrlxup7suptejbacm6rdurdhcaori6i25wylgaikfov4dfgeswxdeerogy2m5tbzsdlr7pfhchd4wnokuipfwjzejxiruj5cljm66hvn47j3eseys3nsi6xdh566jgap5s5e7ytdkkhh5lsuv47oose4luozz427dzk577jccjg3n7b4myd565edmsywol3hgh2i54lcya6saaaaaaa"),
|
1: base32.a2b(b"krqwq33febwxk5dbmjwgkiddn5xhiyljnzsxeidwgefhkckeaohar2c5jzdcrekne6myzpxl2z65d6ufdjuuyhabg2j57ecmy23jyflcp7djzupj4tfr345bkg7cmwxmpmn3h4iaaaaaaaaabb5aaaaaaaaaacsoaaaaaakjl2ynu3sjzjwrfjn4cwfspkueq47j6ej2uodmjsjexyray7dn6ut4nnuftdhhgxo3t3a5eoipsdy5evdihyeigny3c4adtpveplcwt76m7naar2c5jzdcrekne6myzpxl2z65d6ufdjuqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarybcjqw7lbehfrbu7pwx26vvv3mbjprnqup7q7wxmdsoyiqaqzgbtv6cplrrgpzbnptsoqz7imnauamfaaaaaaaaaaamgaaaaaaaaaaaymaaaaghqaaacr4aaaayxaaaagnyaaaaaaaaaao4qaaaaaaaaacd2gcbacibqbudaskugjcdpodibaeaqkaadqiaq2abqqiaqqaucaeaqbvkghg3s5ivqiq4uiajdzagl7iqhz2uxwj6aqk47oscyqxyljmxkapldxhxigum2ejxflnps3yrxwwehop2zairilrouid5s6wxgnoqg2vq7rx77icxfnx7mq65niuknra3tezhpndwo7pdxtvtci645p4umyhdh5gp3kbdpypphvouaql662r6ufigp4wwm6emrsavlontn4wttg6lv7bcmq6ojw5utpvz3agoenovrkndncjzxog7sp2w7l6jkmzgfxd2asxos5khkjbxbuhgkd6j5yqlzsmk3kq67engtlgyd7hxk7nedw73bq2bs4353wtler23poucntgve22acfxdbyj2f6q2saj2agu2ptfk364d3zayddffxkcah4olnkczjonselwwrvdcu3vch3licaeirogosgsui3y4ovcyzleurbiunp7fsfk2fgmiek7b3jogvrhj4snvkpqjfh2w2lqnkvqvuoojmgrn6sll354mpomajbtlsv6fuguzgsxsm3l2ehxdxfdv6kcoyogaa5raetooahunf4ltvfdb4d7mwgpj4pg7tmcw55ku5vgx7tjqkdkuyq2uvhavkbsbujsrcfzve5ekuhftxm7nmtomibrblbwyxcr5mcy6qqwx66lrhejmgewrig74nzpriualhw4g22qaw423qeezqn6irea3vlgc3foz4egf6irincownoq7utv643vmtoueebigwrl6nehbos3ipsdx44tmucpvyui2jzgfulb5mrrcjuycmuzfigu6tf25lbysqn7n7smhqniddgctjt573rtd6o63wiaactacm7dw7giohzcgwe4okbijnmzlacetmfjjbasrd6whexjmwkaiaabdm4cpjolak4m47telnokjaxwodj7ont7n7vffnmhkzp3lyshkh3qaarzybn64ru5rss7tmi4ttv26q66ebdvvrtyd3s5t7dmqku3uoefroaahxhmt46bsa3cpmjfwjyw3zijhhbqh3j2dbc42jaqj6wvmxoz7pecirykndmb6dylde5utzkpucky5pk3x4u6dphkq2ycmfuyvpg5lsudusosyofwfnokbe7qmld2xwaxah3qkywarndsfvp3rybq2y7q42silj5cnlbdxnabv2zhhix3h5o5kz2ttqzm34clnbo527obrxvqlxz3sofwcmz2kqs4c3ypj6o4ny4hkh6qu7ljs7xiygzmoojhnaxc6wjbnvnsu2socztfaegy6ft22tgtdudtok4z755vgj3etwmje73af2f2thks6df52kvobtcnscytmjrrfbekvwmhtbcke2cgcyaj2cra7xmnd4bw2xe2qki5kycopo45ekfyxwzsmxuyxvjzqklnqjwm3j3gwcm75ftnrsvbj33w6eyr4dbz2tewum7vfsyfbb3ojw5ujtn22jxpr4nkmkqup6z7ukpp4cdxwyge2psc5suaxaltmp23gbawoo3qjeo44hgwgtkge2oowox3fpxwxkckaqgrxilfeyxmjp4cwf2rhpkbwtveqkukchv3u5rfkykwfj5zhleu3obsif6ldfclaef32wjpe5d6ddh2grdx2yt6tuhw53t6zuuumlw6t6i3e2ev7nh36e4shwbn3ew2bbahn6imgb5sismfttf5cdlr5kw6wvjoaqiaiz2onxecfx735dvon7epthnklq67tnqj4fvcwechbvmnkpiwd5fd36dirpshc7i7zj3rcr5y3kzps5nfnfnik27gdgemfn27iblcjh5bpkio6sr375bmxbh6fshbo7cvjzsdsirsafnbjzgl6ycqczwbacj5sxwgrzl6qbdhfbzev5fzutznzbasejqdjm3qxsdcuqvqau3kih2anr2itgmr44wmwtsk6bd42m2j436ptslaugmbbvtbzsukeqytkse7niovlilyfssn3ipzkqtclmetqrxxn7h56xn2ju7pjnuamd6ijfawn2jpjsrmnawaozeniosvhgovftoj24dl77ytdkxdl7ogappnlgkqsjyy43urtnj6tqf2psfptkbzyx4nu3rzgsqqi5ybx3pu6cvt6de67xutdz566wrkp2ymy5n7tqchmw77ss532noqcbfxv6quum6jmeed3exasdapvid6bilwzm5dcnutkcxktmsdryqopw5ntws3tnbd7um27clmxkgl2uinwzvv4tmo4axbj5zmgfd6sy2fiw6efdwjcyj4awdx3peuxcyh3ccee63w2nqaltierdrevl3f3hnjsrdrl4aosd23szhhaimhg2mjuocottcdsraoczh3waoyxx2skunaphe6w5gutu2z7cag3cx4pgsspfmspphuunzx357x6l36hj3tdys727rhawfwc4wc4ytgts4nrxlxl3xxzffunlhjhzj5guxljwxfrxwjfsg5c67pg3js7gvfqmpson6rjgiuwbsklranwhauq74lbesavftdzf7y3x5zwbi4uu6q2vqimbkttm7k6ycttsgknej2ylkwdxgtut7wecpepnb527pblj3vuzldjt3whsmstax536plulalxtxmvj6vvg4phofyaidhxhhkl4dfb6oabp3fi55jt77pw3jl55pwbsimjpdanuenll2xxctr6swaimuaqk4wvqa6rbgow3onr74v4alkuukc2tlmorvsjpgaazpun6pbfyorazzarhc2r7fjt55pmosowrqcpdwl2q34hcco2f3icmpktchxdvtpmitufnplqaifbtlktkpo7b22244n6dkmxtgcnxtixsit57uhh7rc5rqezjz7pfd7ojhrui5bcdzb7bo2nbo6o24lpwbg4bmqgbqpbwclq6kglgxefryxlkqydillki3545vcrelfw6reszml6emuyjscx377on2qpq26j5jrh5xmbwmpcyq6sewanlbmwwk2vqhq5zunbcyd6h5z3ms3bgfn7lflvev5vwmjnv5nzbgrmpamy453zuvy6xc6jp7tqgpmrlxup7suptejbacm6rdurdhcaori6i25wylgaikfov4dfgeswxdeerogy2m5tbzsdlr7pfhchd4wnokuipfwjzejxiruj5cljm66hvn47j3eseys3nsi6xdh566jgap5s5e7ytdkkhh5lsuv47oose4luozz427dzk577jccjg3n7b4myd565edmsywol3hgh2i54lcya6saaaaaaa"),
|
||||||
6: base32.a2b("krqwq33febwxk5dbmjwgkiddn5xhiyljnzsxeidwgefhkckeaohar2c5jzdcrekne6myzpxl2z65d6ufdjuuyhabg2j57ecmy23jyflcp7djzupj4tfr345bkg7cmwxmpmn3h4iaaaaaaaaabb5aaaaaaaaaacsoaaaaaakjl2ynu3sjzjwrfjn4cwfspkueq47j6ej2uodmjsjexyray7dn6ut4nnuftdhhgxo3t3a5eoipsdy5evdihyeigny3c4adtpveplcwt76m7naar2c5jzdcrekne6myzpxl2z65d6ufdjuqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarybcjqw7lbehfrbu7pwx26vvv3mbjprnqup7q7wxmdsoyiqaqzgbtv6cplrrgpzbnptsoqz7imnauamfaaaaaaaaaaamgaaaaaaaaaaaymaaaaghqaaacr4aaaayxaaaagnyaaaaaaaaaao4qaaaaaaaaacd2gcbacibqbudaskugjcdpodibaeaqkaadqiaq2abqqiaqqaucaeaqbvkghg3s5ivqiq4uiajdzagl7iqhz2uxwj6aqk47oscyqxyljmxkapldxhxigum2ejxflnps3yrxwwehop2zairilrouid5s6wxgnoqg2vq7rx77icxfnx7mq65niuknra3tezhpndwo7pdxtvtci645p4umyhdh5gp3kbdpypphvouaql662r6ufigp4wwm6emrsavlontn4wttg6lv7bcmq6ojw5utpvz3agoenovrkndncjzxog7sp2w7l6jkmzgfxd2asxos5khkjbxbuhgkd6j5yqlzsmk3kq67engtlgyd7hxk7nedw73bq2bs4353wtler23poucntgve22acfxdbyj2f6q2saj2agu2ptfk364d3zayddffxkcah4olnkczjonselwwrvdcu3vch3licaeirogosgsui3y4ovcyzleurbiunp7fsfk2fgmiek7b3jogvrhj4snvkpqjfh2w2lqnkvqvuoojmgrn6sll354mpomajbtlsv6fuguzgsxsm3l2ehxdxfdv6kcoyogaa5raetooahunf4ltvfdb4d7mwgpj4pg7tmcw55ku5vgx7tjqkdkuyq2uvhavkbsbujsrcfzve5ekuhftxm7nmtomibrblbwyxcr5mcy6qqwx66lrhejmgewrig74nzpriualhw4g22qaw423qeezqn6irea3vlgc3foz4egf6irincownoq7utv643vmtoueebigwrl6nehbos3ipsdx44tmucpvyui2jzgfulb5mrrcjuycmuzfigu6tf25lbysqn7n7smhqniddgctjt573rtd6o63wiaactacm7dw7giohzcgwe4okbijnmzlacetmfjjbasrd6whexjmwkaiaaazuum3xriq54h5v6afcrrl3kkbd46oizwulc5fbslmblxfc3ldyyqaaszc7rkciv6rhwt5gbgnl5u54ihnqrfyuh7s54r2444mrhcwgizieaalkclm4iljq34daut2vffpxdlkklamhwyod66dgimv5alle47lszewah5lt22m7poc3nvamk7462qlijpzfe7cy4x5udwfpuznzy7rlhx7ev5hmvxi5m3nctyofw2axz6a4fttdxoefezaqu7wur2rtcmxx5wxmpdkfflvzvawzr2oecq7yriklbc2nfyk4ezeulmdaktctlwcoz26jt3yx5gg2ez6jnhblc5swn7qbl6t3ebm2fmworvtrpxyqhegsly6xtpbh2yfdu6ww52ypka6cc4crgov33cdnbxyekdmjck2h55ni4othks6df52kvobtcnscytmjrrfbekvwmhtbcke2cgcyaj2cra7xmnd4bw2xe2qki5kycopo45ekfyxwzsmxuyxvjzqklnqjwm3j3gwcm75ftnrsvbj33w6eyr4dbz2tewum7vfsyfbb3ojw5ujtn22jxpr4nkmkqup6z7ukpp4cdxwyge2psc5suaxaltmp23gbawoo3qjeo44hgwgtkge2oowox3fpxwxkckaqgrxilfeyxmjp4cwf2rhpkbwtveqkukchv3u5rfkykwfj5zhleu3obsif6ldfclaef32wjpe5d6ddh2grdx2yt6tuhw53t6zuuumlw6t6i3e2ev7nh36e4shwbn3ew2bbahn6imgb5sismfttf5cdlr5kw6wvjoaqiaiz2onxecfx735dvon7epthnklq67tnqj4fvcwechbvmnkpiwd5fd36dirpshc7i7zj3rcr5y3kzps5nfnfnik27gdgemfn27iblcjh5bpkio6sr375bmxbh6fshbo7cvjzsdsirsafnbjzgl6ycqczwbacj5sxwgrzl6qbdhfbzev5fzutznzbasejqdjm3qxsdcuqvqau3kih2anr2itgmr44wmwtsk6bd42m2j436ptslaugmbbvtbzsukeqytkse7niovlilyfssn3ipzkqtclmetqrxxn7h56xn2ju7pjnuamd6ijfawn2jpjsrmnawaozeniosvhgovftoj24dl77ytdkxdl7ogappnlgkqsjyy43urtnj6tqf2psfptkbzyx4nu3rzgsqqi5ybx3pu6cvt6de67xutdz566wrkp2ymy5n7tqchmw77ss532noqcbfxv6quum6jmeed3exasdapvid6bilwzm5dcnutkcxktmsdryqopw5ntws3tnbd7um27clmxkgl2uinwzvv4tmo4axbj5zmgfd6sy2fiw6efdwjcyj4awdx3peuxcyh3ccee63w2nqaltierdrevl3f3hnjsrdrl4aosd23szhhaimhg2mjuocottcdsraoczh3waoyxx2skunaphe6w5gutu2z7cag3cx4pgsspfmspphuunzx357x6l36hj3tdys727rhawfwc4wc4ytgts4nrxlxl3xxzffunlhjhzj5guxljwxfrxwjfsg5c67pg3js7gvfqmpson6rjgiuwbsklranwhauq74lbesavftdzf7y3x5zwbi4uu6q2vqimbkttm7k6ycttsgknej2ylkwdxgtut7wecpepnb527pblj3vuzldjt3whsmstax536plulalxtxmvj6vvg4phofyaidhxhhkl4dfb6oabp3fi55jt77pw3jl55pwbsimjpdanuenll2xxctr6swaimuaqk4wvqa6rbgow3onr74v4alkuukc2tlmorvsjpgaazpun6pbfyorazzarhc2r7fjt55pmosowrqcpdwl2q34hcco2f3icmpktchxdvtpmitufnplqaifbtlktkpo7b22244n6dkmxtgcnxtixsit57uhh7rc5rqezjz7pfd7ojhrui5bcdzb7bo2nbo6o24lpwbg4bmqgbqpbwclq6kglgxefryxlkqydillki3545vcrelfw6reszml6emuyjscx377on2qpq26j5jrh5xmbwmpcyq6sewanlbmwwk2vqhq5zunbcyd6h5z3ms3bgfn7lflvev5vwmjnv5nzbgrmpamy453zuvy6xc6jp7tqgpmrlxup7suptejbacm6rdurdhcaori6i25wylgaikfov4dfgeswxdeerogy2m5tbzsdlr7pfhchd4wnokuipfwjzejxiruj5cljm66hvn47j3eseys3nsi6xdh566jgap5s5e7ytdkkhh5lsuv47oose4luozz427dzk577jccjg3n7b4myd565edmsywol3hgh2i54lcya6saaaaaaa"),
|
6: base32.a2b(b"krqwq33febwxk5dbmjwgkiddn5xhiyljnzsxeidwgefhkckeaohar2c5jzdcrekne6myzpxl2z65d6ufdjuuyhabg2j57ecmy23jyflcp7djzupj4tfr345bkg7cmwxmpmn3h4iaaaaaaaaabb5aaaaaaaaaacsoaaaaaakjl2ynu3sjzjwrfjn4cwfspkueq47j6ej2uodmjsjexyray7dn6ut4nnuftdhhgxo3t3a5eoipsdy5evdihyeigny3c4adtpveplcwt76m7naar2c5jzdcrekne6myzpxl2z65d6ufdjuqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarybcjqw7lbehfrbu7pwx26vvv3mbjprnqup7q7wxmdsoyiqaqzgbtv6cplrrgpzbnptsoqz7imnauamfaaaaaaaaaaamgaaaaaaaaaaaymaaaaghqaaacr4aaaayxaaaagnyaaaaaaaaaao4qaaaaaaaaacd2gcbacibqbudaskugjcdpodibaeaqkaadqiaq2abqqiaqqaucaeaqbvkghg3s5ivqiq4uiajdzagl7iqhz2uxwj6aqk47oscyqxyljmxkapldxhxigum2ejxflnps3yrxwwehop2zairilrouid5s6wxgnoqg2vq7rx77icxfnx7mq65niuknra3tezhpndwo7pdxtvtci645p4umyhdh5gp3kbdpypphvouaql662r6ufigp4wwm6emrsavlontn4wttg6lv7bcmq6ojw5utpvz3agoenovrkndncjzxog7sp2w7l6jkmzgfxd2asxos5khkjbxbuhgkd6j5yqlzsmk3kq67engtlgyd7hxk7nedw73bq2bs4353wtler23poucntgve22acfxdbyj2f6q2saj2agu2ptfk364d3zayddffxkcah4olnkczjonselwwrvdcu3vch3licaeirogosgsui3y4ovcyzleurbiunp7fsfk2fgmiek7b3jogvrhj4snvkpqjfh2w2lqnkvqvuoojmgrn6sll354mpomajbtlsv6fuguzgsxsm3l2ehxdxfdv6kcoyogaa5raetooahunf4ltvfdb4d7mwgpj4pg7tmcw55ku5vgx7tjqkdkuyq2uvhavkbsbujsrcfzve5ekuhftxm7nmtomibrblbwyxcr5mcy6qqwx66lrhejmgewrig74nzpriualhw4g22qaw423qeezqn6irea3vlgc3foz4egf6irincownoq7utv643vmtoueebigwrl6nehbos3ipsdx44tmucpvyui2jzgfulb5mrrcjuycmuzfigu6tf25lbysqn7n7smhqniddgctjt573rtd6o63wiaactacm7dw7giohzcgwe4okbijnmzlacetmfjjbasrd6whexjmwkaiaaazuum3xriq54h5v6afcrrl3kkbd46oizwulc5fbslmblxfc3ldyyqaaszc7rkciv6rhwt5gbgnl5u54ihnqrfyuh7s54r2444mrhcwgizieaalkclm4iljq34daut2vffpxdlkklamhwyod66dgimv5alle47lszewah5lt22m7poc3nvamk7462qlijpzfe7cy4x5udwfpuznzy7rlhx7ev5hmvxi5m3nctyofw2axz6a4fttdxoefezaqu7wur2rtcmxx5wxmpdkfflvzvawzr2oecq7yriklbc2nfyk4ezeulmdaktctlwcoz26jt3yx5gg2ez6jnhblc5swn7qbl6t3ebm2fmworvtrpxyqhegsly6xtpbh2yfdu6ww52ypka6cc4crgov33cdnbxyekdmjck2h55ni4othks6df52kvobtcnscytmjrrfbekvwmhtbcke2cgcyaj2cra7xmnd4bw2xe2qki5kycopo45ekfyxwzsmxuyxvjzqklnqjwm3j3gwcm75ftnrsvbj33w6eyr4dbz2tewum7vfsyfbb3ojw5ujtn22jxpr4nkmkqup6z7ukpp4cdxwyge2psc5suaxaltmp23gbawoo3qjeo44hgwgtkge2oowox3fpxwxkckaqgrxilfeyxmjp4cwf2rhpkbwtveqkukchv3u5rfkykwfj5zhleu3obsif6ldfclaef32wjpe5d6ddh2grdx2yt6tuhw53t6zuuumlw6t6i3e2ev7nh36e4shwbn3ew2bbahn6imgb5sismfttf5cdlr5kw6wvjoaqiaiz2onxecfx735dvon7epthnklq67tnqj4fvcwechbvmnkpiwd5fd36dirpshc7i7zj3rcr5y3kzps5nfnfnik27gdgemfn27iblcjh5bpkio6sr375bmxbh6fshbo7cvjzsdsirsafnbjzgl6ycqczwbacj5sxwgrzl6qbdhfbzev5fzutznzbasejqdjm3qxsdcuqvqau3kih2anr2itgmr44wmwtsk6bd42m2j436ptslaugmbbvtbzsukeqytkse7niovlilyfssn3ipzkqtclmetqrxxn7h56xn2ju7pjnuamd6ijfawn2jpjsrmnawaozeniosvhgovftoj24dl77ytdkxdl7ogappnlgkqsjyy43urtnj6tqf2psfptkbzyx4nu3rzgsqqi5ybx3pu6cvt6de67xutdz566wrkp2ymy5n7tqchmw77ss532noqcbfxv6quum6jmeed3exasdapvid6bilwzm5dcnutkcxktmsdryqopw5ntws3tnbd7um27clmxkgl2uinwzvv4tmo4axbj5zmgfd6sy2fiw6efdwjcyj4awdx3peuxcyh3ccee63w2nqaltierdrevl3f3hnjsrdrl4aosd23szhhaimhg2mjuocottcdsraoczh3waoyxx2skunaphe6w5gutu2z7cag3cx4pgsspfmspphuunzx357x6l36hj3tdys727rhawfwc4wc4ytgts4nrxlxl3xxzffunlhjhzj5guxljwxfrxwjfsg5c67pg3js7gvfqmpson6rjgiuwbsklranwhauq74lbesavftdzf7y3x5zwbi4uu6q2vqimbkttm7k6ycttsgknej2ylkwdxgtut7wecpepnb527pblj3vuzldjt3whsmstax536plulalxtxmvj6vvg4phofyaidhxhhkl4dfb6oabp3fi55jt77pw3jl55pwbsimjpdanuenll2xxctr6swaimuaqk4wvqa6rbgow3onr74v4alkuukc2tlmorvsjpgaazpun6pbfyorazzarhc2r7fjt55pmosowrqcpdwl2q34hcco2f3icmpktchxdvtpmitufnplqaifbtlktkpo7b22244n6dkmxtgcnxtixsit57uhh7rc5rqezjz7pfd7ojhrui5bcdzb7bo2nbo6o24lpwbg4bmqgbqpbwclq6kglgxefryxlkqydillki3545vcrelfw6reszml6emuyjscx377on2qpq26j5jrh5xmbwmpcyq6sewanlbmwwk2vqhq5zunbcyd6h5z3ms3bgfn7lflvev5vwmjnv5nzbgrmpamy453zuvy6xc6jp7tqgpmrlxup7suptejbacm6rdurdhcaori6i25wylgaikfov4dfgeswxdeerogy2m5tbzsdlr7pfhchd4wnokuipfwjzejxiruj5cljm66hvn47j3eseys3nsi6xdh566jgap5s5e7ytdkkhh5lsuv47oose4luozz427dzk577jccjg3n7b4myd565edmsywol3hgh2i54lcya6saaaaaaa"),
|
||||||
},
|
},
|
||||||
4: { # client[4]
|
4: { # client[4]
|
||||||
0: base32.a2b("krqwq33febwxk5dbmjwgkiddn5xhiyljnzsxeidwgefhkckeaohanguihdeqshi3vbil354mnoip7yzj3rpsvjbydjlngiqocl2s6dja4dqjzuaghaekxoithualnjp6artv6laaaaaaaaaabb5aaaaaaaaaacsoaaaaaakjl2ynvzguwqjavmynllmjm66qaqz4uh4dinujrxcaafvp5vvzrgueu3fxwkppvopapdw3p4hjezva23vxif5rzgacysmyo7tr4tjd44nnqpsanguihdeqshi3vbil354mnoip7yzj3rpqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarybcjqw7lbehfrbu7pwx26vvv3mbjprnqup7q7wxmdsoyiqaqzgbtv6cplrrgpzbnptsoqz7imnauamfaaaaaaaaaaamgaaaaaaaaaaaymaaaaghqaaacr4aaaayxaaaagnyaaaaaaaaaao4qaaaaaaaaacd2gcbacibqbudaskugjcdpodibaeaqkaadqiaq2abqqiaqqaucaeaqbvkghg3s5ivqiq4uiajdzagl7iqhz2uxwj6aqk47oscyqxyljmxkapldxhxigum2ejxflnps3yrxwwehop2zairilrouid5s6wxgnoqg2vq7rx77icxfnx7mq65niuknra3tezhpndwo7pdxtvtci645p4umyhdh5gp3kbdpypphvouaql662r6ufigp4wwm6emrsavlontn4wttg6lv7bcmq6ojw5utpvz3agoenovrkndncjzxog7sp2w7l6jkmzgfxd2asxos5khkjbxbuhgkd6j5yqlzsmk3kq67engtlgyd7hxk7nedw73bq2bs4353wtler23poucntgve22acfxdbyj2f6q2saj2agu2ptfk364d3zayddffxkcah4olnkczjonselwwrvdcu3vch3licaeirogosgsui3y4ovcyzleurbiunp7fsfk2fgmiek7b3jogvrhj4snvkpqjfh2w2lqnkvqvuoojmgrn6sll354mpomajbtlsv6fuguzgsxsm3l2ehxdxfdv6kcoyogaa5raetooahunf4ltvfdb4d7mwgpj4pg7tmcw55ku5vgx7tjqkdkuyq2uvhavkbsbujsrcfzve5ekuhftxm7nmtomibrblbwyxcr5mcy6qqwx66lrhejmgewrig74nzpriualhw4g22qaw423qeezqn6irea3vlgc3foz4egf6irincownoq7utv643vmtoueebigwrl6nehbos3ipsdx44tmucpvyui2jzgfulb5mrrcjuycmuzfigu6tf25lbysqn7n7smhqniddgctjt573rtd6o63wiaactacm7dw7giohzcgwe4okbijnmzlacetmfjjbasrd6whexjmwkaiaabdm4cpjolak4m47telnokjaxwodj7ont7n7vffnmhkzp3lyshkh3qaarzybn64ru5rss7tmi4ttv26q66ebdvvrtyd3s5t7dmqku3uoefroaaibdqu2gyd4hqwgj3jhsu7ievr26vxpzj4g6ovbvqeyljrk6n2xfidtwj6pazanrhwes3e4ln4uettqyd5u5bqroneqie7lkwlxm7xsbg4zhnlc2fybonhlpcatwlgdvk3jpn7sge4qnod2ufxgxc7rphbnunb52xrgmdgpojqhyfajxealxwdddlhhbttphrgv5zrub5mggbcec3honrtuuv3epex3s5yvkt2zmsaxfeu34psjwjltm4ys5qa72ryrmgjtmtu3i34jfmachhmgul2j2sddwydgvtpqnatglb3ejlhukxp3isthks6df52kvobtcnscytmjrrfbekvwmhtbcke2cgcyaj2cra7xmnd4bw2xe2qki5kycopo45ekfyxwzsmxuyxvjzqklnqjwm3j3gwcm75ftnrsvbj33w6eyr4dbz2tewum7vfsyfbb3ojw5ujtn22jxpr4nkmkqup6z7ukpp4cdxwyge2psc5suaxaltmp23gbawoo3qjeo44hgwgtkge2oowox3fpxwxkckaqgrxilfeyxmjp4cwf2rhpkbwtveqkukchv3u5rfkykwfj5zhleu3obsif6ldfclaef32wjpe5d6ddh2grdx2yt6tuhw53t6zuuumlw6t6i3e2ev7nh36e4shwbn3ew2bbahn6imgb5sismfttf5cdlr5kw6wvjoaqiaiz2onxecfx735dvon7epthnklq67tnqj4fvcwechbvmnkpiwd5fd36dirpshc7i7zj3rcr5y3kzps5nfnfnik27gdgemfn27iblcjh5bpkio6sr375bmxbh6fshbo7cvjzsdsirsafnbjzgl6ycqczwbacj5sxwgrzl6qbdhfbzev5fzutznzbasejqdjm3qxsdcuqvqau3kih2anr2itgmr44wmwtsk6bd42m2j436ptslaugmbbvtbzsukeqytkse7niovlilyfssn3ipzkqtclmetqrxxn7h56xn2ju7pjnuamd6ijfawn2jpjsrmnawaozeniosvhgovftoj24dl77ytdkxdl7ogappnlgkqsjyy43urtnj6tqf2psfptkbzyx4nu3rzgsqqi5ybx3pu6cvt6de67xutdz566wrkp2ymy5n7tqchmw77ss532noqcbfxv6quum6jmeed3exasdapvid6bilwzm5dcnutkcxktmsdryqopw5ntws3tnbd7um27clmxkgl2uinwzvv4tmo4axbj5zmgfd6sy2fiw6efdwjcyj4awdx3peuxcyh3ccee63w2nqaltierdrevl3f3hnjsrdrl4aosd23szhhaimhg2mjuocottcdsraoczh3waoyxx2skunaphe6w5gutu2z7cag3cx4pgsspfmspphuunzx357x6l36hj3tdys727rhawfwc4wc4ytgts4nrxlxl3xxzffunlhjhzj5guxljwxfrxwjfsg5c67pg3js7gvfqmpson6rjgiuwbsklranwhauq74lbesavftdzf7y3x5zwbi4uu6q2vqimbkttm7k6ycttsgknej2ylkwdxgtut7wecpepnb527pblj3vuzldjt3whsmstax536plulalxtxmvj6vvg4phofyaidhxhhkl4dfb6oabp3fi55jt77pw3jl55pwbsimjpdanuenll2xxctr6swaimuaqk4wvqa6rbgow3onr74v4alkuukc2tlmorvsjpgaazpun6pbfyorazzarhc2r7fjt55pmosowrqcpdwl2q34hcco2f3icmpktchxdvtpmitufnplqaifbtlktkpo7b22244n6dkmxtgcnxtixsit57uhh7rc5rqezjz7pfd7ojhrui5bcdzb7bo2nbo6o24lpwbg4bmqgbqpbwclq6kglgxefryxlkqydillki3545vcrelfw6reszml6emuyjscx377on2qpq26j5jrh5xmbwmpcyq6sewanlbmwwk2vqhq5zunbcyd6h5z3ms3bgfn7lflvev5vwmjnv5nzbgrmpamy453zuvy6xc6jp7tqgpmrlxup7suptejbacm6rdurdhcaori6i25wylgaikfov4dfgeswxdeerogy2m5tbzsdlr7pfhchd4wnokuipfwjzejxiruj5cljm66hvn47j3eseys3nsi6xdh566jgap5s5e7ytdkkhh5lsuv47oose4luozz427dzk577jccjg3n7b4myd565edmsywol3hgh2i54lcya6saaaaaaa"),
|
0: base32.a2b(b"krqwq33febwxk5dbmjwgkiddn5xhiyljnzsxeidwgefhkckeaohanguihdeqshi3vbil354mnoip7yzj3rpsvjbydjlngiqocl2s6dja4dqjzuaghaekxoithualnjp6artv6laaaaaaaaaabb5aaaaaaaaaacsoaaaaaakjl2ynvzguwqjavmynllmjm66qaqz4uh4dinujrxcaafvp5vvzrgueu3fxwkppvopapdw3p4hjezva23vxif5rzgacysmyo7tr4tjd44nnqpsanguihdeqshi3vbil354mnoip7yzj3rpqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarybcjqw7lbehfrbu7pwx26vvv3mbjprnqup7q7wxmdsoyiqaqzgbtv6cplrrgpzbnptsoqz7imnauamfaaaaaaaaaaamgaaaaaaaaaaaymaaaaghqaaacr4aaaayxaaaagnyaaaaaaaaaao4qaaaaaaaaacd2gcbacibqbudaskugjcdpodibaeaqkaadqiaq2abqqiaqqaucaeaqbvkghg3s5ivqiq4uiajdzagl7iqhz2uxwj6aqk47oscyqxyljmxkapldxhxigum2ejxflnps3yrxwwehop2zairilrouid5s6wxgnoqg2vq7rx77icxfnx7mq65niuknra3tezhpndwo7pdxtvtci645p4umyhdh5gp3kbdpypphvouaql662r6ufigp4wwm6emrsavlontn4wttg6lv7bcmq6ojw5utpvz3agoenovrkndncjzxog7sp2w7l6jkmzgfxd2asxos5khkjbxbuhgkd6j5yqlzsmk3kq67engtlgyd7hxk7nedw73bq2bs4353wtler23poucntgve22acfxdbyj2f6q2saj2agu2ptfk364d3zayddffxkcah4olnkczjonselwwrvdcu3vch3licaeirogosgsui3y4ovcyzleurbiunp7fsfk2fgmiek7b3jogvrhj4snvkpqjfh2w2lqnkvqvuoojmgrn6sll354mpomajbtlsv6fuguzgsxsm3l2ehxdxfdv6kcoyogaa5raetooahunf4ltvfdb4d7mwgpj4pg7tmcw55ku5vgx7tjqkdkuyq2uvhavkbsbujsrcfzve5ekuhftxm7nmtomibrblbwyxcr5mcy6qqwx66lrhejmgewrig74nzpriualhw4g22qaw423qeezqn6irea3vlgc3foz4egf6irincownoq7utv643vmtoueebigwrl6nehbos3ipsdx44tmucpvyui2jzgfulb5mrrcjuycmuzfigu6tf25lbysqn7n7smhqniddgctjt573rtd6o63wiaactacm7dw7giohzcgwe4okbijnmzlacetmfjjbasrd6whexjmwkaiaabdm4cpjolak4m47telnokjaxwodj7ont7n7vffnmhkzp3lyshkh3qaarzybn64ru5rss7tmi4ttv26q66ebdvvrtyd3s5t7dmqku3uoefroaaibdqu2gyd4hqwgj3jhsu7ievr26vxpzj4g6ovbvqeyljrk6n2xfidtwj6pazanrhwes3e4ln4uettqyd5u5bqroneqie7lkwlxm7xsbg4zhnlc2fybonhlpcatwlgdvk3jpn7sge4qnod2ufxgxc7rphbnunb52xrgmdgpojqhyfajxealxwdddlhhbttphrgv5zrub5mggbcec3honrtuuv3epex3s5yvkt2zmsaxfeu34psjwjltm4ys5qa72ryrmgjtmtu3i34jfmachhmgul2j2sddwydgvtpqnatglb3ejlhukxp3isthks6df52kvobtcnscytmjrrfbekvwmhtbcke2cgcyaj2cra7xmnd4bw2xe2qki5kycopo45ekfyxwzsmxuyxvjzqklnqjwm3j3gwcm75ftnrsvbj33w6eyr4dbz2tewum7vfsyfbb3ojw5ujtn22jxpr4nkmkqup6z7ukpp4cdxwyge2psc5suaxaltmp23gbawoo3qjeo44hgwgtkge2oowox3fpxwxkckaqgrxilfeyxmjp4cwf2rhpkbwtveqkukchv3u5rfkykwfj5zhleu3obsif6ldfclaef32wjpe5d6ddh2grdx2yt6tuhw53t6zuuumlw6t6i3e2ev7nh36e4shwbn3ew2bbahn6imgb5sismfttf5cdlr5kw6wvjoaqiaiz2onxecfx735dvon7epthnklq67tnqj4fvcwechbvmnkpiwd5fd36dirpshc7i7zj3rcr5y3kzps5nfnfnik27gdgemfn27iblcjh5bpkio6sr375bmxbh6fshbo7cvjzsdsirsafnbjzgl6ycqczwbacj5sxwgrzl6qbdhfbzev5fzutznzbasejqdjm3qxsdcuqvqau3kih2anr2itgmr44wmwtsk6bd42m2j436ptslaugmbbvtbzsukeqytkse7niovlilyfssn3ipzkqtclmetqrxxn7h56xn2ju7pjnuamd6ijfawn2jpjsrmnawaozeniosvhgovftoj24dl77ytdkxdl7ogappnlgkqsjyy43urtnj6tqf2psfptkbzyx4nu3rzgsqqi5ybx3pu6cvt6de67xutdz566wrkp2ymy5n7tqchmw77ss532noqcbfxv6quum6jmeed3exasdapvid6bilwzm5dcnutkcxktmsdryqopw5ntws3tnbd7um27clmxkgl2uinwzvv4tmo4axbj5zmgfd6sy2fiw6efdwjcyj4awdx3peuxcyh3ccee63w2nqaltierdrevl3f3hnjsrdrl4aosd23szhhaimhg2mjuocottcdsraoczh3waoyxx2skunaphe6w5gutu2z7cag3cx4pgsspfmspphuunzx357x6l36hj3tdys727rhawfwc4wc4ytgts4nrxlxl3xxzffunlhjhzj5guxljwxfrxwjfsg5c67pg3js7gvfqmpson6rjgiuwbsklranwhauq74lbesavftdzf7y3x5zwbi4uu6q2vqimbkttm7k6ycttsgknej2ylkwdxgtut7wecpepnb527pblj3vuzldjt3whsmstax536plulalxtxmvj6vvg4phofyaidhxhhkl4dfb6oabp3fi55jt77pw3jl55pwbsimjpdanuenll2xxctr6swaimuaqk4wvqa6rbgow3onr74v4alkuukc2tlmorvsjpgaazpun6pbfyorazzarhc2r7fjt55pmosowrqcpdwl2q34hcco2f3icmpktchxdvtpmitufnplqaifbtlktkpo7b22244n6dkmxtgcnxtixsit57uhh7rc5rqezjz7pfd7ojhrui5bcdzb7bo2nbo6o24lpwbg4bmqgbqpbwclq6kglgxefryxlkqydillki3545vcrelfw6reszml6emuyjscx377on2qpq26j5jrh5xmbwmpcyq6sewanlbmwwk2vqhq5zunbcyd6h5z3ms3bgfn7lflvev5vwmjnv5nzbgrmpamy453zuvy6xc6jp7tqgpmrlxup7suptejbacm6rdurdhcaori6i25wylgaikfov4dfgeswxdeerogy2m5tbzsdlr7pfhchd4wnokuipfwjzejxiruj5cljm66hvn47j3eseys3nsi6xdh566jgap5s5e7ytdkkhh5lsuv47oose4luozz427dzk577jccjg3n7b4myd565edmsywol3hgh2i54lcya6saaaaaaa"),
|
||||||
5: base32.a2b("krqwq33febwxk5dbmjwgkiddn5xhiyljnzsxeidwgefhkckeaohanguihdeqshi3vbil354mnoip7yzj3rpsvjbydjlngiqocl2s6dja4dqjzuaghaekxoithualnjp6artv6laaaaaaaaaabb5aaaaaaaaaacsoaaaaaakjl2ynvzguwqjavmynllmjm66qaqz4uh4dinujrxcaafvp5vvzrgueu3fxwkppvopapdw3p4hjezva23vxif5rzgacysmyo7tr4tjd44nnqpsanguihdeqshi3vbil354mnoip7yzj3rpqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarybcjqw7lbehfrbu7pwx26vvv3mbjprnqup7q7wxmdsoyiqaqzgbtv6cplrrgpzbnptsoqz7imnauamfaaaaaaaaaaamgaaaaaaaaaaaymaaaaghqaaacr4aaaayxaaaagnyaaaaaaaaaao4qaaaaaaaaacd2gcbacibqbudaskugjcdpodibaeaqkaadqiaq2abqqiaqqaucaeaqbvkghg3s5ivqiq4uiajdzagl7iqhz2uxwj6aqk47oscyqxyljmxkapldxhxigum2ejxflnps3yrxwwehop2zairilrouid5s6wxgnoqg2vq7rx77icxfnx7mq65niuknra3tezhpndwo7pdxtvtci645p4umyhdh5gp3kbdpypphvouaql662r6ufigp4wwm6emrsavlontn4wttg6lv7bcmq6ojw5utpvz3agoenovrkndncjzxog7sp2w7l6jkmzgfxd2asxos5khkjbxbuhgkd6j5yqlzsmk3kq67engtlgyd7hxk7nedw73bq2bs4353wtler23poucntgve22acfxdbyj2f6q2saj2agu2ptfk364d3zayddffxkcah4olnkczjonselwwrvdcu3vch3licaeirogosgsui3y4ovcyzleurbiunp7fsfk2fgmiek7b3jogvrhj4snvkpqjfh2w2lqnkvqvuoojmgrn6sll354mpomajbtlsv6fuguzgsxsm3l2ehxdxfdv6kcoyogaa5raetooahunf4ltvfdb4d7mwgpj4pg7tmcw55ku5vgx7tjqkdkuyq2uvhavkbsbujsrcfzve5ekuhftxm7nmtomibrblbwyxcr5mcy6qqwx66lrhejmgewrig74nzpriualhw4g22qaw423qeezqn6irea3vlgc3foz4egf6irincownoq7utv643vmtoueebigwrl6nehbos3ipsdx44tmucpvyui2jzgfulb5mrrcjuycmuzfigu6tf25lbysqn7n7smhqniddgctjt573rtd6o63wiaactacm7dw7giohzcgwe4okbijnmzlacetmfjjbasrd6whexjmwkaiaaazuum3xriq54h5v6afcrrl3kkbd46oizwulc5fbslmblxfc3ldyyqaavmjy6g336aewy42vw5rusytyi7vzs6y22c5jhxyt5w6gthcbjp4zaajwnpw5yhhwh4hyctajptujjwg7cswzjkwucke6yvbuejqhrnbafadv245phzjfluujm5pyfx43oagwtsdkgtw2v4i56uexjrumsdes6go7556an26wmzpbskyrsx4qbzqcedilovhlkrlnhvsfr4mjwkw62mkf4kde7jgesu4ztbzc7xmuobydnxk5hdyyly6n7socvrsqw6z56v6osxr2vgxpz6jor7ciyclkungeaayume5hdrm6cbnvwgua4gc2fcpixfdbkiijnmlicribyoinnpu6zdce4mdfqyl4qzup3kkk5qju2wthks6df52kvobtcnscytmjrrfbekvwmhtbcke2cgcyaj2cra7xmnd4bw2xe2qki5kycopo45ekfyxwzsmxuyxvjzqklnqjwm3j3gwcm75ftnrsvbj33w6eyr4dbz2tewum7vfsyfbb3ojw5ujtn22jxpr4nkmkqup6z7ukpp4cdxwyge2psc5suaxaltmp23gbawoo3qjeo44hgwgtkge2oowox3fpxwxkckaqgrxilfeyxmjp4cwf2rhpkbwtveqkukchv3u5rfkykwfj5zhleu3obsif6ldfclaef32wjpe5d6ddh2grdx2yt6tuhw53t6zuuumlw6t6i3e2ev7nh36e4shwbn3ew2bbahn6imgb5sismfttf5cdlr5kw6wvjoaqiaiz2onxecfx735dvon7epthnklq67tnqj4fvcwechbvmnkpiwd5fd36dirpshc7i7zj3rcr5y3kzps5nfnfnik27gdgemfn27iblcjh5bpkio6sr375bmxbh6fshbo7cvjzsdsirsafnbjzgl6ycqczwbacj5sxwgrzl6qbdhfbzev5fzutznzbasejqdjm3qxsdcuqvqau3kih2anr2itgmr44wmwtsk6bd42m2j436ptslaugmbbvtbzsukeqytkse7niovlilyfssn3ipzkqtclmetqrxxn7h56xn2ju7pjnuamd6ijfawn2jpjsrmnawaozeniosvhgovftoj24dl77ytdkxdl7ogappnlgkqsjyy43urtnj6tqf2psfptkbzyx4nu3rzgsqqi5ybx3pu6cvt6de67xutdz566wrkp2ymy5n7tqchmw77ss532noqcbfxv6quum6jmeed3exasdapvid6bilwzm5dcnutkcxktmsdryqopw5ntws3tnbd7um27clmxkgl2uinwzvv4tmo4axbj5zmgfd6sy2fiw6efdwjcyj4awdx3peuxcyh3ccee63w2nqaltierdrevl3f3hnjsrdrl4aosd23szhhaimhg2mjuocottcdsraoczh3waoyxx2skunaphe6w5gutu2z7cag3cx4pgsspfmspphuunzx357x6l36hj3tdys727rhawfwc4wc4ytgts4nrxlxl3xxzffunlhjhzj5guxljwxfrxwjfsg5c67pg3js7gvfqmpson6rjgiuwbsklranwhauq74lbesavftdzf7y3x5zwbi4uu6q2vqimbkttm7k6ycttsgknej2ylkwdxgtut7wecpepnb527pblj3vuzldjt3whsmstax536plulalxtxmvj6vvg4phofyaidhxhhkl4dfb6oabp3fi55jt77pw3jl55pwbsimjpdanuenll2xxctr6swaimuaqk4wvqa6rbgow3onr74v4alkuukc2tlmorvsjpgaazpun6pbfyorazzarhc2r7fjt55pmosowrqcpdwl2q34hcco2f3icmpktchxdvtpmitufnplqaifbtlktkpo7b22244n6dkmxtgcnxtixsit57uhh7rc5rqezjz7pfd7ojhrui5bcdzb7bo2nbo6o24lpwbg4bmqgbqpbwclq6kglgxefryxlkqydillki3545vcrelfw6reszml6emuyjscx377on2qpq26j5jrh5xmbwmpcyq6sewanlbmwwk2vqhq5zunbcyd6h5z3ms3bgfn7lflvev5vwmjnv5nzbgrmpamy453zuvy6xc6jp7tqgpmrlxup7suptejbacm6rdurdhcaori6i25wylgaikfov4dfgeswxdeerogy2m5tbzsdlr7pfhchd4wnokuipfwjzejxiruj5cljm66hvn47j3eseys3nsi6xdh566jgap5s5e7ytdkkhh5lsuv47oose4luozz427dzk577jccjg3n7b4myd565edmsywol3hgh2i54lcya6saaaaaaa"),
|
5: base32.a2b(b"krqwq33febwxk5dbmjwgkiddn5xhiyljnzsxeidwgefhkckeaohanguihdeqshi3vbil354mnoip7yzj3rpsvjbydjlngiqocl2s6dja4dqjzuaghaekxoithualnjp6artv6laaaaaaaaaabb5aaaaaaaaaacsoaaaaaakjl2ynvzguwqjavmynllmjm66qaqz4uh4dinujrxcaafvp5vvzrgueu3fxwkppvopapdw3p4hjezva23vxif5rzgacysmyo7tr4tjd44nnqpsanguihdeqshi3vbil354mnoip7yzj3rpqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarybcjqw7lbehfrbu7pwx26vvv3mbjprnqup7q7wxmdsoyiqaqzgbtv6cplrrgpzbnptsoqz7imnauamfaaaaaaaaaaamgaaaaaaaaaaaymaaaaghqaaacr4aaaayxaaaagnyaaaaaaaaaao4qaaaaaaaaacd2gcbacibqbudaskugjcdpodibaeaqkaadqiaq2abqqiaqqaucaeaqbvkghg3s5ivqiq4uiajdzagl7iqhz2uxwj6aqk47oscyqxyljmxkapldxhxigum2ejxflnps3yrxwwehop2zairilrouid5s6wxgnoqg2vq7rx77icxfnx7mq65niuknra3tezhpndwo7pdxtvtci645p4umyhdh5gp3kbdpypphvouaql662r6ufigp4wwm6emrsavlontn4wttg6lv7bcmq6ojw5utpvz3agoenovrkndncjzxog7sp2w7l6jkmzgfxd2asxos5khkjbxbuhgkd6j5yqlzsmk3kq67engtlgyd7hxk7nedw73bq2bs4353wtler23poucntgve22acfxdbyj2f6q2saj2agu2ptfk364d3zayddffxkcah4olnkczjonselwwrvdcu3vch3licaeirogosgsui3y4ovcyzleurbiunp7fsfk2fgmiek7b3jogvrhj4snvkpqjfh2w2lqnkvqvuoojmgrn6sll354mpomajbtlsv6fuguzgsxsm3l2ehxdxfdv6kcoyogaa5raetooahunf4ltvfdb4d7mwgpj4pg7tmcw55ku5vgx7tjqkdkuyq2uvhavkbsbujsrcfzve5ekuhftxm7nmtomibrblbwyxcr5mcy6qqwx66lrhejmgewrig74nzpriualhw4g22qaw423qeezqn6irea3vlgc3foz4egf6irincownoq7utv643vmtoueebigwrl6nehbos3ipsdx44tmucpvyui2jzgfulb5mrrcjuycmuzfigu6tf25lbysqn7n7smhqniddgctjt573rtd6o63wiaactacm7dw7giohzcgwe4okbijnmzlacetmfjjbasrd6whexjmwkaiaaazuum3xriq54h5v6afcrrl3kkbd46oizwulc5fbslmblxfc3ldyyqaavmjy6g336aewy42vw5rusytyi7vzs6y22c5jhxyt5w6gthcbjp4zaajwnpw5yhhwh4hyctajptujjwg7cswzjkwucke6yvbuejqhrnbafadv245phzjfluujm5pyfx43oagwtsdkgtw2v4i56uexjrumsdes6go7556an26wmzpbskyrsx4qbzqcedilovhlkrlnhvsfr4mjwkw62mkf4kde7jgesu4ztbzc7xmuobydnxk5hdyyly6n7socvrsqw6z56v6osxr2vgxpz6jor7ciyclkungeaayume5hdrm6cbnvwgua4gc2fcpixfdbkiijnmlicribyoinnpu6zdce4mdfqyl4qzup3kkk5qju2wthks6df52kvobtcnscytmjrrfbekvwmhtbcke2cgcyaj2cra7xmnd4bw2xe2qki5kycopo45ekfyxwzsmxuyxvjzqklnqjwm3j3gwcm75ftnrsvbj33w6eyr4dbz2tewum7vfsyfbb3ojw5ujtn22jxpr4nkmkqup6z7ukpp4cdxwyge2psc5suaxaltmp23gbawoo3qjeo44hgwgtkge2oowox3fpxwxkckaqgrxilfeyxmjp4cwf2rhpkbwtveqkukchv3u5rfkykwfj5zhleu3obsif6ldfclaef32wjpe5d6ddh2grdx2yt6tuhw53t6zuuumlw6t6i3e2ev7nh36e4shwbn3ew2bbahn6imgb5sismfttf5cdlr5kw6wvjoaqiaiz2onxecfx735dvon7epthnklq67tnqj4fvcwechbvmnkpiwd5fd36dirpshc7i7zj3rcr5y3kzps5nfnfnik27gdgemfn27iblcjh5bpkio6sr375bmxbh6fshbo7cvjzsdsirsafnbjzgl6ycqczwbacj5sxwgrzl6qbdhfbzev5fzutznzbasejqdjm3qxsdcuqvqau3kih2anr2itgmr44wmwtsk6bd42m2j436ptslaugmbbvtbzsukeqytkse7niovlilyfssn3ipzkqtclmetqrxxn7h56xn2ju7pjnuamd6ijfawn2jpjsrmnawaozeniosvhgovftoj24dl77ytdkxdl7ogappnlgkqsjyy43urtnj6tqf2psfptkbzyx4nu3rzgsqqi5ybx3pu6cvt6de67xutdz566wrkp2ymy5n7tqchmw77ss532noqcbfxv6quum6jmeed3exasdapvid6bilwzm5dcnutkcxktmsdryqopw5ntws3tnbd7um27clmxkgl2uinwzvv4tmo4axbj5zmgfd6sy2fiw6efdwjcyj4awdx3peuxcyh3ccee63w2nqaltierdrevl3f3hnjsrdrl4aosd23szhhaimhg2mjuocottcdsraoczh3waoyxx2skunaphe6w5gutu2z7cag3cx4pgsspfmspphuunzx357x6l36hj3tdys727rhawfwc4wc4ytgts4nrxlxl3xxzffunlhjhzj5guxljwxfrxwjfsg5c67pg3js7gvfqmpson6rjgiuwbsklranwhauq74lbesavftdzf7y3x5zwbi4uu6q2vqimbkttm7k6ycttsgknej2ylkwdxgtut7wecpepnb527pblj3vuzldjt3whsmstax536plulalxtxmvj6vvg4phofyaidhxhhkl4dfb6oabp3fi55jt77pw3jl55pwbsimjpdanuenll2xxctr6swaimuaqk4wvqa6rbgow3onr74v4alkuukc2tlmorvsjpgaazpun6pbfyorazzarhc2r7fjt55pmosowrqcpdwl2q34hcco2f3icmpktchxdvtpmitufnplqaifbtlktkpo7b22244n6dkmxtgcnxtixsit57uhh7rc5rqezjz7pfd7ojhrui5bcdzb7bo2nbo6o24lpwbg4bmqgbqpbwclq6kglgxefryxlkqydillki3545vcrelfw6reszml6emuyjscx377on2qpq26j5jrh5xmbwmpcyq6sewanlbmwwk2vqhq5zunbcyd6h5z3ms3bgfn7lflvev5vwmjnv5nzbgrmpamy453zuvy6xc6jp7tqgpmrlxup7suptejbacm6rdurdhcaori6i25wylgaikfov4dfgeswxdeerogy2m5tbzsdlr7pfhchd4wnokuipfwjzejxiruj5cljm66hvn47j3eseys3nsi6xdh566jgap5s5e7ytdkkhh5lsuv47oose4luozz427dzk577jccjg3n7b4myd565edmsywol3hgh2i54lcya6saaaaaaa"),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
#--------- END stored_shares.py ----------------
|
#--------- END stored_shares.py ----------------
|
||||||
@ -92,7 +102,7 @@ class _Base(GridTestMixin, ShouldFailMixin):
|
|||||||
def _created_immutable(ur):
|
def _created_immutable(ur):
|
||||||
# write the generated shares and URI to a file, which can then be
|
# write the generated shares and URI to a file, which can then be
|
||||||
# incorporated into this one next time.
|
# incorporated into this one next time.
|
||||||
f.write('immutable_uri = "%s"\n' % ur.get_uri())
|
f.write('immutable_uri = b"%s"\n' % ur.get_uri())
|
||||||
f.write('immutable_shares = {\n')
|
f.write('immutable_shares = {\n')
|
||||||
si = uri.from_string(ur.get_uri()).get_storage_index()
|
si = uri.from_string(ur.get_uri()).get_storage_index()
|
||||||
si_dir = storage_index_to_dir(si)
|
si_dir = storage_index_to_dir(si)
|
||||||
@ -107,7 +117,7 @@ class _Base(GridTestMixin, ShouldFailMixin):
|
|||||||
if shares:
|
if shares:
|
||||||
f.write(' %d: { # client[%d]\n' % (i, i))
|
f.write(' %d: { # client[%d]\n' % (i, i))
|
||||||
for shnum in sorted(shares.keys()):
|
for shnum in sorted(shares.keys()):
|
||||||
f.write(' %d: base32.a2b("%s"),\n' %
|
f.write(' %d: base32.a2b(b"%s"),\n' %
|
||||||
(shnum, base32.b2a(shares[shnum])))
|
(shnum, base32.b2a(shares[shnum])))
|
||||||
f.write(' },\n')
|
f.write(' },\n')
|
||||||
f.write('}\n')
|
f.write('}\n')
|
||||||
@ -118,7 +128,7 @@ class _Base(GridTestMixin, ShouldFailMixin):
|
|||||||
d.addCallback(lambda ignored:
|
d.addCallback(lambda ignored:
|
||||||
self.c0.create_mutable_file(mutable_plaintext))
|
self.c0.create_mutable_file(mutable_plaintext))
|
||||||
def _created_mutable(n):
|
def _created_mutable(n):
|
||||||
f.write('mutable_uri = "%s"\n' % n.get_uri())
|
f.write('mutable_uri = b"%s"\n' % n.get_uri())
|
||||||
f.write('mutable_shares = {\n')
|
f.write('mutable_shares = {\n')
|
||||||
si = uri.from_string(n.get_uri()).get_storage_index()
|
si = uri.from_string(n.get_uri()).get_storage_index()
|
||||||
si_dir = storage_index_to_dir(si)
|
si_dir = storage_index_to_dir(si)
|
||||||
@ -133,7 +143,7 @@ class _Base(GridTestMixin, ShouldFailMixin):
|
|||||||
if shares:
|
if shares:
|
||||||
f.write(' %d: { # client[%d]\n' % (i, i))
|
f.write(' %d: { # client[%d]\n' % (i, i))
|
||||||
for shnum in sorted(shares.keys()):
|
for shnum in sorted(shares.keys()):
|
||||||
f.write(' %d: base32.a2b("%s"),\n' %
|
f.write(' %d: base32.a2b(b"%s"),\n' %
|
||||||
(shnum, base32.b2a(shares[shnum])))
|
(shnum, base32.b2a(shares[shnum])))
|
||||||
f.write(' },\n')
|
f.write(' },\n')
|
||||||
f.write('}\n')
|
f.write('}\n')
|
||||||
@ -312,7 +322,7 @@ class DownloadTest(_Base, unittest.TestCase):
|
|||||||
return self.n.read(c)
|
return self.n.read(c)
|
||||||
d.addCallback(_download_again)
|
d.addCallback(_download_again)
|
||||||
def _check_failover(c):
|
def _check_failover(c):
|
||||||
self.failUnlessEqual("".join(c.chunks), plaintext)
|
self.failUnlessEqual(b"".join(c.chunks), plaintext)
|
||||||
shares = self.n._cnode._node._shares
|
shares = self.n._cnode._node._shares
|
||||||
shnums = sorted([s._shnum for s in shares])
|
shnums = sorted([s._shnum for s in shares])
|
||||||
self.failIfEqual(shnums, self.killed_share_nums)
|
self.failIfEqual(shnums, self.killed_share_nums)
|
||||||
@ -331,8 +341,8 @@ class DownloadTest(_Base, unittest.TestCase):
|
|||||||
n = self.c0.create_node_from_uri(immutable_uri)
|
n = self.c0.create_node_from_uri(immutable_uri)
|
||||||
|
|
||||||
c = MemoryConsumer()
|
c = MemoryConsumer()
|
||||||
d = n.read(c, long(0), long(10))
|
d = n.read(c, int(0), int(10))
|
||||||
d.addCallback(lambda c: len("".join(c.chunks)))
|
d.addCallback(lambda c: len(b"".join(c.chunks)))
|
||||||
d.addCallback(lambda size: self.failUnlessEqual(size, 10))
|
d.addCallback(lambda size: self.failUnlessEqual(size, 10))
|
||||||
return d
|
return d
|
||||||
|
|
||||||
@ -356,7 +366,7 @@ class DownloadTest(_Base, unittest.TestCase):
|
|||||||
# really there's only one segment
|
# really there's only one segment
|
||||||
d = n.read(con1, 180, 20)
|
d = n.read(con1, 180, 20)
|
||||||
def _done(res):
|
def _done(res):
|
||||||
self.failUnlessEqual("".join(con1.chunks), plaintext[180:200])
|
self.failUnlessEqual(b"".join(con1.chunks), plaintext[180:200])
|
||||||
d.addCallback(_done)
|
d.addCallback(_done)
|
||||||
return d
|
return d
|
||||||
|
|
||||||
@ -381,8 +391,8 @@ class DownloadTest(_Base, unittest.TestCase):
|
|||||||
return defer.gatherResults([d1,d2])
|
return defer.gatherResults([d1,d2])
|
||||||
d.addCallback(_uploaded)
|
d.addCallback(_uploaded)
|
||||||
def _done(res):
|
def _done(res):
|
||||||
self.failUnlessEqual("".join(con1.chunks), plaintext[70:90])
|
self.failUnlessEqual(b"".join(con1.chunks), plaintext[70:90])
|
||||||
self.failUnlessEqual("".join(con2.chunks), plaintext[140:160])
|
self.failUnlessEqual(b"".join(con2.chunks), plaintext[140:160])
|
||||||
d.addCallback(_done)
|
d.addCallback(_done)
|
||||||
return d
|
return d
|
||||||
|
|
||||||
@ -408,8 +418,8 @@ class DownloadTest(_Base, unittest.TestCase):
|
|||||||
return defer.gatherResults([d1,d2])
|
return defer.gatherResults([d1,d2])
|
||||||
d.addCallback(_uploaded)
|
d.addCallback(_uploaded)
|
||||||
def _done(res):
|
def _done(res):
|
||||||
self.failUnlessEqual("".join(con1.chunks), plaintext[70:90])
|
self.failUnlessEqual(b"".join(con1.chunks), plaintext[70:90])
|
||||||
self.failUnlessEqual("".join(con2.chunks), plaintext[140:160])
|
self.failUnlessEqual(b"".join(con2.chunks), plaintext[140:160])
|
||||||
d.addCallback(_done)
|
d.addCallback(_done)
|
||||||
return d
|
return d
|
||||||
|
|
||||||
@ -433,11 +443,11 @@ class DownloadTest(_Base, unittest.TestCase):
|
|||||||
n._cnode._node._build_guessed_tables(u.max_segment_size)
|
n._cnode._node._build_guessed_tables(u.max_segment_size)
|
||||||
d = n.read(con1, 12000, 20)
|
d = n.read(con1, 12000, 20)
|
||||||
def _read1(ign):
|
def _read1(ign):
|
||||||
self.failUnlessEqual("".join(con1.chunks), data[12000:12020])
|
self.failUnlessEqual(b"".join(con1.chunks), data[12000:12020])
|
||||||
return n.read(con2, 24000, 20)
|
return n.read(con2, 24000, 20)
|
||||||
d.addCallback(_read1)
|
d.addCallback(_read1)
|
||||||
def _read2(ign):
|
def _read2(ign):
|
||||||
self.failUnlessEqual("".join(con2.chunks), data[24000:24020])
|
self.failUnlessEqual(b"".join(con2.chunks), data[24000:24020])
|
||||||
d.addCallback(_read2)
|
d.addCallback(_read2)
|
||||||
return d
|
return d
|
||||||
d.addCallback(_uploaded)
|
d.addCallback(_uploaded)
|
||||||
@ -517,15 +527,15 @@ class DownloadTest(_Base, unittest.TestCase):
|
|||||||
# corrupt all the shares so the download will fail
|
# corrupt all the shares so the download will fail
|
||||||
def _corruptor(s, debug=False):
|
def _corruptor(s, debug=False):
|
||||||
which = 48 # first byte of block0
|
which = 48 # first byte of block0
|
||||||
return s[:which] + chr(ord(s[which])^0x01) + s[which+1:]
|
return s[:which] + bchr(ord(s[which:which+1])^0x01) + s[which+1:]
|
||||||
self.corrupt_all_shares(ur.get_uri(), _corruptor)
|
self.corrupt_all_shares(ur.get_uri(), _corruptor)
|
||||||
n = self.c0.create_node_from_uri(ur.get_uri())
|
n = self.c0.create_node_from_uri(ur.get_uri())
|
||||||
n._cnode._maybe_create_download_node()
|
n._cnode._maybe_create_download_node()
|
||||||
n._cnode._node._build_guessed_tables(u.max_segment_size)
|
n._cnode._node._build_guessed_tables(u.max_segment_size)
|
||||||
con1 = MemoryConsumer()
|
con1 = MemoryConsumer()
|
||||||
con2 = MemoryConsumer()
|
con2 = MemoryConsumer()
|
||||||
d = n.read(con1, long(0), long(20))
|
d = n.read(con1, int(0), int(20))
|
||||||
d2 = n.read(con2, long(140), long(20))
|
d2 = n.read(con2, int(140), int(20))
|
||||||
# con2 will be cancelled, so d2 should fail with DownloadStopped
|
# con2 will be cancelled, so d2 should fail with DownloadStopped
|
||||||
def _con2_should_not_succeed(res):
|
def _con2_should_not_succeed(res):
|
||||||
self.fail("the second read should not have succeeded")
|
self.fail("the second read should not have succeeded")
|
||||||
@ -558,15 +568,15 @@ class DownloadTest(_Base, unittest.TestCase):
|
|||||||
# corrupt all the shares so the download will fail
|
# corrupt all the shares so the download will fail
|
||||||
def _corruptor(s, debug=False):
|
def _corruptor(s, debug=False):
|
||||||
which = 48 # first byte of block0
|
which = 48 # first byte of block0
|
||||||
return s[:which] + chr(ord(s[which])^0x01) + s[which+1:]
|
return s[:which] + bchr(ord(s[which:which+1])^0x01) + s[which+1:]
|
||||||
self.corrupt_all_shares(ur.get_uri(), _corruptor)
|
self.corrupt_all_shares(ur.get_uri(), _corruptor)
|
||||||
n = self.c0.create_node_from_uri(ur.get_uri())
|
n = self.c0.create_node_from_uri(ur.get_uri())
|
||||||
n._cnode._maybe_create_download_node()
|
n._cnode._maybe_create_download_node()
|
||||||
n._cnode._node._build_guessed_tables(u.max_segment_size)
|
n._cnode._node._build_guessed_tables(u.max_segment_size)
|
||||||
con1 = MemoryConsumer()
|
con1 = MemoryConsumer()
|
||||||
con2 = MemoryConsumer()
|
con2 = MemoryConsumer()
|
||||||
d = n.read(con1, long(0), long(20))
|
d = n.read(con1, int(0), int(20))
|
||||||
d2 = n.read(con2, long(140), long(20))
|
d2 = n.read(con2, int(140), int(20))
|
||||||
# con2 should wait for con1 to fail and then con2 should succeed.
|
# con2 should wait for con1 to fail and then con2 should succeed.
|
||||||
# In particular, we should not lose progress. If this test fails,
|
# In particular, we should not lose progress. If this test fails,
|
||||||
# it will fail with a timeout error.
|
# it will fail with a timeout error.
|
||||||
@ -574,7 +584,7 @@ class DownloadTest(_Base, unittest.TestCase):
|
|||||||
# this should succeed because we only corrupted the first
|
# this should succeed because we only corrupted the first
|
||||||
# segment of each share. The segment that holds [140:160] is
|
# segment of each share. The segment that holds [140:160] is
|
||||||
# fine, as are the hash chains and UEB.
|
# fine, as are the hash chains and UEB.
|
||||||
self.failUnlessEqual("".join(con2.chunks), plaintext[140:160])
|
self.failUnlessEqual(b"".join(con2.chunks), plaintext[140:160])
|
||||||
d2.addCallback(_con2_should_succeed)
|
d2.addCallback(_con2_should_succeed)
|
||||||
|
|
||||||
def _con1_should_not_succeed(res):
|
def _con1_should_not_succeed(res):
|
||||||
@ -602,8 +612,8 @@ class DownloadTest(_Base, unittest.TestCase):
|
|||||||
# the share. This exercises a different code path.
|
# the share. This exercises a different code path.
|
||||||
for s in self.c0.storage_broker.get_connected_servers():
|
for s in self.c0.storage_broker.get_connected_servers():
|
||||||
v = s.get_version()
|
v = s.get_version()
|
||||||
v1 = v["http://allmydata.org/tahoe/protocols/storage/v1"]
|
v1 = v[b"http://allmydata.org/tahoe/protocols/storage/v1"]
|
||||||
v1["tolerates-immutable-read-overrun"] = False
|
v1[b"tolerates-immutable-read-overrun"] = False
|
||||||
|
|
||||||
n = self.c0.create_node_from_uri(immutable_uri)
|
n = self.c0.create_node_from_uri(immutable_uri)
|
||||||
d = download_to_data(n)
|
d = download_to_data(n)
|
||||||
@ -687,7 +697,7 @@ class DownloadTest(_Base, unittest.TestCase):
|
|||||||
c = PausingConsumer()
|
c = PausingConsumer()
|
||||||
d = n.read(c)
|
d = n.read(c)
|
||||||
def _downloaded(mc):
|
def _downloaded(mc):
|
||||||
newdata = "".join(mc.chunks)
|
newdata = b"".join(mc.chunks)
|
||||||
self.failUnlessEqual(newdata, plaintext)
|
self.failUnlessEqual(newdata, plaintext)
|
||||||
d.addCallback(_downloaded)
|
d.addCallback(_downloaded)
|
||||||
return d
|
return d
|
||||||
@ -823,8 +833,8 @@ class DownloadTest(_Base, unittest.TestCase):
|
|||||||
return defer.gatherResults([d1,d2])
|
return defer.gatherResults([d1,d2])
|
||||||
d.addCallback(_uploaded)
|
d.addCallback(_uploaded)
|
||||||
def _done(res):
|
def _done(res):
|
||||||
self.failUnlessEqual("".join(con1.chunks), plaintext[70:90])
|
self.failUnlessEqual(b"".join(con1.chunks), plaintext[70:90])
|
||||||
self.failUnlessEqual("".join(con2.chunks), plaintext[140:160])
|
self.failUnlessEqual(b"".join(con2.chunks), plaintext[140:160])
|
||||||
#d.addCallback(_done)
|
#d.addCallback(_done)
|
||||||
return d
|
return d
|
||||||
|
|
||||||
@ -877,7 +887,7 @@ class BrokenDecoder(CRSDecoder):
|
|||||||
d = CRSDecoder.decode(self, shares, shareids)
|
d = CRSDecoder.decode(self, shares, shareids)
|
||||||
def _decoded(buffers):
|
def _decoded(buffers):
|
||||||
def _corruptor(s, which):
|
def _corruptor(s, which):
|
||||||
return s[:which] + chr(ord(s[which])^0x01) + s[which+1:]
|
return s[:which] + bchr(ord(s[which:which+1])^0x01) + s[which+1:]
|
||||||
buffers[0] = _corruptor(buffers[0], 0) # flip lsb of first byte
|
buffers[0] = _corruptor(buffers[0], 0) # flip lsb of first byte
|
||||||
return buffers
|
return buffers
|
||||||
d.addCallback(_decoded)
|
d.addCallback(_decoded)
|
||||||
@ -937,13 +947,13 @@ class Corruption(_Base, unittest.TestCase):
|
|||||||
def _corrupt_flip(self, ign, imm_uri, which):
|
def _corrupt_flip(self, ign, imm_uri, which):
|
||||||
log.msg("corrupt %d" % which)
|
log.msg("corrupt %d" % which)
|
||||||
def _corruptor(s, debug=False):
|
def _corruptor(s, debug=False):
|
||||||
return s[:which] + chr(ord(s[which])^0x01) + s[which+1:]
|
return s[:which] + bchr(ord(s[which:which+1])^0x01) + s[which+1:]
|
||||||
self.corrupt_shares_numbered(imm_uri, [2], _corruptor)
|
self.corrupt_shares_numbered(imm_uri, [2], _corruptor)
|
||||||
|
|
||||||
def _corrupt_set(self, ign, imm_uri, which, newvalue):
|
def _corrupt_set(self, ign, imm_uri, which, newvalue):
|
||||||
log.msg("corrupt %d" % which)
|
log.msg("corrupt %d" % which)
|
||||||
def _corruptor(s, debug=False):
|
def _corruptor(s, debug=False):
|
||||||
return s[:which] + chr(newvalue) + s[which+1:]
|
return s[:which] + bchr(newvalue) + s[which+1:]
|
||||||
self.corrupt_shares_numbered(imm_uri, [2], _corruptor)
|
self.corrupt_shares_numbered(imm_uri, [2], _corruptor)
|
||||||
|
|
||||||
def test_each_byte(self):
|
def test_each_byte(self):
|
||||||
@ -1047,7 +1057,7 @@ class Corruption(_Base, unittest.TestCase):
|
|||||||
[(i, "2bad-need-3") for i in need3_victims] +
|
[(i, "2bad-need-3") for i in need3_victims] +
|
||||||
[(i, "need-4th") for i in need_4th_victims])
|
[(i, "need-4th") for i in need_4th_victims])
|
||||||
if self.catalog_detection:
|
if self.catalog_detection:
|
||||||
share_len = len(self.shares.values()[0])
|
share_len = len(list(self.shares.values())[0])
|
||||||
corrupt_me = [(i, "") for i in range(share_len)]
|
corrupt_me = [(i, "") for i in range(share_len)]
|
||||||
# This is a work around for ticket #2024.
|
# This is a work around for ticket #2024.
|
||||||
corrupt_me = corrupt_me[0:8]+corrupt_me[12:]
|
corrupt_me = corrupt_me[0:8]+corrupt_me[12:]
|
||||||
@ -1069,7 +1079,7 @@ class Corruption(_Base, unittest.TestCase):
|
|||||||
return d
|
return d
|
||||||
d.addCallback(_uploaded)
|
d.addCallback(_uploaded)
|
||||||
def _show_results(ign):
|
def _show_results(ign):
|
||||||
share_len = len(self.shares.values()[0])
|
share_len = len(list(self.shares.values())[0])
|
||||||
print()
|
print()
|
||||||
print("of [0:%d], corruption ignored in %s" %
|
print("of [0:%d], corruption ignored in %s" %
|
||||||
(share_len, undetected.dump()))
|
(share_len, undetected.dump()))
|
||||||
@ -1136,7 +1146,7 @@ class Corruption(_Base, unittest.TestCase):
|
|||||||
|
|
||||||
def _corrupt_flip_all(self, ign, imm_uri, which):
|
def _corrupt_flip_all(self, ign, imm_uri, which):
|
||||||
def _corruptor(s, debug=False):
|
def _corruptor(s, debug=False):
|
||||||
return s[:which] + chr(ord(s[which])^0x01) + s[which+1:]
|
return s[:which] + bchr(ord(s[which:which+1])^0x01) + s[which+1:]
|
||||||
self.corrupt_all_shares(imm_uri, _corruptor)
|
self.corrupt_all_shares(imm_uri, _corruptor)
|
||||||
|
|
||||||
class DownloadV2(_Base, unittest.TestCase):
|
class DownloadV2(_Base, unittest.TestCase):
|
||||||
@ -1179,8 +1189,8 @@ class DownloadV2(_Base, unittest.TestCase):
|
|||||||
# the share. This exercises a different code path.
|
# the share. This exercises a different code path.
|
||||||
for s in self.c0.storage_broker.get_connected_servers():
|
for s in self.c0.storage_broker.get_connected_servers():
|
||||||
v = s.get_version()
|
v = s.get_version()
|
||||||
v1 = v["http://allmydata.org/tahoe/protocols/storage/v1"]
|
v1 = v[b"http://allmydata.org/tahoe/protocols/storage/v1"]
|
||||||
v1["tolerates-immutable-read-overrun"] = False
|
v1[b"tolerates-immutable-read-overrun"] = False
|
||||||
|
|
||||||
# upload a file
|
# upload a file
|
||||||
u = upload.Data(plaintext, None)
|
u = upload.Data(plaintext, None)
|
||||||
@ -1279,7 +1289,7 @@ class Status(unittest.TestCase):
|
|||||||
self.failUnlessEqual(ds.get_active(), False)
|
self.failUnlessEqual(ds.get_active(), False)
|
||||||
|
|
||||||
def make_server(clientid):
|
def make_server(clientid):
|
||||||
tubid = hashutil.tagged_hash("clientid", clientid)[:20]
|
tubid = hashutil.tagged_hash(b"clientid", clientid)[:20]
|
||||||
return NoNetworkServer(tubid, None)
|
return NoNetworkServer(tubid, None)
|
||||||
def make_servers(clientids):
|
def make_servers(clientids):
|
||||||
servers = {}
|
servers = {}
|
||||||
@ -1344,7 +1354,7 @@ class Selection(unittest.TestCase):
|
|||||||
def test_only_one_share(self):
|
def test_only_one_share(self):
|
||||||
node = FakeNode()
|
node = FakeNode()
|
||||||
sf = MySegmentFetcher(node, 0, 3, None)
|
sf = MySegmentFetcher(node, 0, 3, None)
|
||||||
serverA = make_server("peer-A")
|
serverA = make_server(b"peer-A")
|
||||||
shares = [MyShare(0, serverA, 0.0)]
|
shares = [MyShare(0, serverA, 0.0)]
|
||||||
sf.add_shares(shares)
|
sf.add_shares(shares)
|
||||||
d = flushEventualQueue()
|
d = flushEventualQueue()
|
||||||
@ -1366,7 +1376,7 @@ class Selection(unittest.TestCase):
|
|||||||
def test_good_diversity_early(self):
|
def test_good_diversity_early(self):
|
||||||
node = FakeNode()
|
node = FakeNode()
|
||||||
sf = MySegmentFetcher(node, 0, 3, None)
|
sf = MySegmentFetcher(node, 0, 3, None)
|
||||||
shares = [MyShare(i, make_server("peer-%d" % i), i) for i in range(10)]
|
shares = [MyShare(i, make_server(b"peer-%d" % i), i) for i in range(10)]
|
||||||
sf.add_shares(shares)
|
sf.add_shares(shares)
|
||||||
d = flushEventualQueue()
|
d = flushEventualQueue()
|
||||||
def _check1(ign):
|
def _check1(ign):
|
||||||
@ -1388,7 +1398,7 @@ class Selection(unittest.TestCase):
|
|||||||
def test_good_diversity_late(self):
|
def test_good_diversity_late(self):
|
||||||
node = FakeNode()
|
node = FakeNode()
|
||||||
sf = MySegmentFetcher(node, 0, 3, None)
|
sf = MySegmentFetcher(node, 0, 3, None)
|
||||||
shares = [MyShare(i, make_server("peer-%d" % i), i) for i in range(10)]
|
shares = [MyShare(i, make_server(b"peer-%d" % i), i) for i in range(10)]
|
||||||
sf.add_shares([])
|
sf.add_shares([])
|
||||||
d = flushEventualQueue()
|
d = flushEventualQueue()
|
||||||
def _check1(ign):
|
def _check1(ign):
|
||||||
@ -1417,12 +1427,12 @@ class Selection(unittest.TestCase):
|
|||||||
# we could satisfy the read entirely from the first server, but we'd
|
# we could satisfy the read entirely from the first server, but we'd
|
||||||
# prefer not to. Instead, we expect to only pull one share from the
|
# prefer not to. Instead, we expect to only pull one share from the
|
||||||
# first server
|
# first server
|
||||||
servers = make_servers(["peer-A", "peer-B", "peer-C"])
|
servers = make_servers([b"peer-A", b"peer-B", b"peer-C"])
|
||||||
shares = [MyShare(0, servers["peer-A"], 0.0),
|
shares = [MyShare(0, servers[b"peer-A"], 0.0),
|
||||||
MyShare(1, servers["peer-A"], 0.0),
|
MyShare(1, servers[b"peer-A"], 0.0),
|
||||||
MyShare(2, servers["peer-A"], 0.0),
|
MyShare(2, servers[b"peer-A"], 0.0),
|
||||||
MyShare(3, servers["peer-B"], 1.0),
|
MyShare(3, servers[b"peer-B"], 1.0),
|
||||||
MyShare(4, servers["peer-C"], 2.0),
|
MyShare(4, servers[b"peer-C"], 2.0),
|
||||||
]
|
]
|
||||||
sf.add_shares([])
|
sf.add_shares([])
|
||||||
d = flushEventualQueue()
|
d = flushEventualQueue()
|
||||||
@ -1452,7 +1462,7 @@ class Selection(unittest.TestCase):
|
|||||||
sf = MySegmentFetcher(node, 0, 3, None)
|
sf = MySegmentFetcher(node, 0, 3, None)
|
||||||
# we satisfy the read entirely from the first server because we don't
|
# we satisfy the read entirely from the first server because we don't
|
||||||
# have any other choice.
|
# have any other choice.
|
||||||
serverA = make_server("peer-A")
|
serverA = make_server(b"peer-A")
|
||||||
shares = [MyShare(0, serverA, 0.0),
|
shares = [MyShare(0, serverA, 0.0),
|
||||||
MyShare(1, serverA, 0.0),
|
MyShare(1, serverA, 0.0),
|
||||||
MyShare(2, serverA, 0.0),
|
MyShare(2, serverA, 0.0),
|
||||||
@ -1488,7 +1498,7 @@ class Selection(unittest.TestCase):
|
|||||||
sf = MySegmentFetcher(node, 0, 3, None)
|
sf = MySegmentFetcher(node, 0, 3, None)
|
||||||
# we satisfy the read entirely from the first server because we don't
|
# we satisfy the read entirely from the first server because we don't
|
||||||
# have any other choice.
|
# have any other choice.
|
||||||
serverA = make_server("peer-A")
|
serverA = make_server(b"peer-A")
|
||||||
shares = [MyShare(0, serverA, 0.0),
|
shares = [MyShare(0, serverA, 0.0),
|
||||||
MyShare(1, serverA, 0.0),
|
MyShare(1, serverA, 0.0),
|
||||||
MyShare(2, serverA, 0.0),
|
MyShare(2, serverA, 0.0),
|
||||||
@ -1517,7 +1527,7 @@ class Selection(unittest.TestCase):
|
|||||||
def test_overdue(self):
|
def test_overdue(self):
|
||||||
node = FakeNode()
|
node = FakeNode()
|
||||||
sf = MySegmentFetcher(node, 0, 3, None)
|
sf = MySegmentFetcher(node, 0, 3, None)
|
||||||
shares = [MyShare(i, make_server("peer-%d" % i), i) for i in range(10)]
|
shares = [MyShare(i, make_server(b"peer-%d" % i), i) for i in range(10)]
|
||||||
sf.add_shares(shares)
|
sf.add_shares(shares)
|
||||||
d = flushEventualQueue()
|
d = flushEventualQueue()
|
||||||
def _check1(ign):
|
def _check1(ign):
|
||||||
@ -1545,8 +1555,8 @@ class Selection(unittest.TestCase):
|
|||||||
def test_overdue_fails(self):
|
def test_overdue_fails(self):
|
||||||
node = FakeNode()
|
node = FakeNode()
|
||||||
sf = MySegmentFetcher(node, 0, 3, None)
|
sf = MySegmentFetcher(node, 0, 3, None)
|
||||||
servers = make_servers(["peer-%d" % i for i in range(6)])
|
servers = make_servers([b"peer-%d" % i for i in range(6)])
|
||||||
shares = [MyShare(i, servers["peer-%d" % i], i) for i in range(6)]
|
shares = [MyShare(i, servers[b"peer-%d" % i], i) for i in range(6)]
|
||||||
sf.add_shares(shares)
|
sf.add_shares(shares)
|
||||||
sf.no_more_shares()
|
sf.no_more_shares()
|
||||||
d = flushEventualQueue()
|
d = flushEventualQueue()
|
||||||
@ -1579,7 +1589,7 @@ class Selection(unittest.TestCase):
|
|||||||
def _check4(ign):
|
def _check4(ign):
|
||||||
self.failUnless(node.failed)
|
self.failUnless(node.failed)
|
||||||
self.failUnless(node.failed.check(NotEnoughSharesError))
|
self.failUnless(node.failed.check(NotEnoughSharesError))
|
||||||
sname = servers["peer-2"].get_name()
|
sname = servers[b"peer-2"].get_name()
|
||||||
self.failUnlessIn("complete=sh0 pending= overdue=sh2-on-%s unused=" % sname,
|
self.failUnlessIn("complete=sh0 pending= overdue=sh2-on-%s unused=" % sname,
|
||||||
str(node.failed))
|
str(node.failed))
|
||||||
d.addCallback(_check4)
|
d.addCallback(_check4)
|
||||||
@ -1591,13 +1601,13 @@ class Selection(unittest.TestCase):
|
|||||||
# we could satisfy the read entirely from the first server, but we'd
|
# we could satisfy the read entirely from the first server, but we'd
|
||||||
# prefer not to. Instead, we expect to only pull one share from the
|
# prefer not to. Instead, we expect to only pull one share from the
|
||||||
# first server
|
# first server
|
||||||
servers = make_servers(["peer-A", "peer-B", "peer-C", "peer-D",
|
servers = make_servers([b"peer-A", b"peer-B", b"peer-C", b"peer-D",
|
||||||
"peer-E"])
|
b"peer-E"])
|
||||||
shares = [MyShare(0, servers["peer-A"],0.0),
|
shares = [MyShare(0, servers[b"peer-A"],0.0),
|
||||||
MyShare(1, servers["peer-B"],1.0),
|
MyShare(1, servers[b"peer-B"],1.0),
|
||||||
MyShare(0, servers["peer-C"],2.0), # this will be skipped
|
MyShare(0, servers[b"peer-C"],2.0), # this will be skipped
|
||||||
MyShare(1, servers["peer-D"],3.0),
|
MyShare(1, servers[b"peer-D"],3.0),
|
||||||
MyShare(2, servers["peer-E"],4.0),
|
MyShare(2, servers[b"peer-E"],4.0),
|
||||||
]
|
]
|
||||||
sf.add_shares(shares[:3])
|
sf.add_shares(shares[:3])
|
||||||
d = flushEventualQueue()
|
d = flushEventualQueue()
|
||||||
|
@ -1,3 +1,14 @@
|
|||||||
|
"""
|
||||||
|
Ported to Python 3.
|
||||||
|
"""
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import division
|
||||||
|
from __future__ import print_function
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from future.utils import PY2
|
||||||
|
if PY2:
|
||||||
|
from future.builtins import filter, map, zip, ascii, chr, hex, input, next, oct, open, pow, round, super, bytes, dict, list, object, range, str, max, min # noqa: F401
|
||||||
|
|
||||||
from twisted.trial import unittest
|
from twisted.trial import unittest
|
||||||
from allmydata import uri, client
|
from allmydata import uri, client
|
||||||
@ -22,12 +33,12 @@ class FakeClient(object):
|
|||||||
return None
|
return None
|
||||||
def get_history(self):
|
def get_history(self):
|
||||||
return None
|
return None
|
||||||
_secret_holder = client.SecretHolder("lease secret", "convergence secret")
|
_secret_holder = client.SecretHolder(b"lease secret", b"convergence secret")
|
||||||
|
|
||||||
class Node(unittest.TestCase):
|
class Node(unittest.TestCase):
|
||||||
def test_chk_filenode(self):
|
def test_chk_filenode(self):
|
||||||
u = uri.CHKFileURI(key="\x00"*16,
|
u = uri.CHKFileURI(key=b"\x00"*16,
|
||||||
uri_extension_hash="\x00"*32,
|
uri_extension_hash=b"\x00"*32,
|
||||||
needed_shares=3,
|
needed_shares=3,
|
||||||
total_shares=10,
|
total_shares=10,
|
||||||
size=1000)
|
size=1000)
|
||||||
@ -59,7 +70,7 @@ class Node(unittest.TestCase):
|
|||||||
|
|
||||||
|
|
||||||
def test_literal_filenode(self):
|
def test_literal_filenode(self):
|
||||||
DATA = "I am a short file."
|
DATA = b"I am a short file."
|
||||||
u = uri.LiteralFileURI(data=DATA)
|
u = uri.LiteralFileURI(data=DATA)
|
||||||
fn1 = LiteralFileNode(u)
|
fn1 = LiteralFileNode(u)
|
||||||
fn2 = LiteralFileNode(u)
|
fn2 = LiteralFileNode(u)
|
||||||
@ -114,11 +125,11 @@ class Node(unittest.TestCase):
|
|||||||
|
|
||||||
def test_mutable_filenode(self):
|
def test_mutable_filenode(self):
|
||||||
client = FakeClient()
|
client = FakeClient()
|
||||||
wk = "\x00"*16
|
wk = b"\x00"*16
|
||||||
rk = hashutil.ssk_readkey_hash(wk)
|
rk = hashutil.ssk_readkey_hash(wk)
|
||||||
si = hashutil.ssk_storage_index_hash(rk)
|
si = hashutil.ssk_storage_index_hash(rk)
|
||||||
|
|
||||||
u = uri.WriteableSSKFileURI("\x00"*16, "\x00"*32)
|
u = uri.WriteableSSKFileURI(b"\x00"*16, b"\x00"*32)
|
||||||
n = MutableFileNode(None, None, client.get_encoding_parameters(),
|
n = MutableFileNode(None, None, client.get_encoding_parameters(),
|
||||||
None).init_from_cap(u)
|
None).init_from_cap(u)
|
||||||
|
|
||||||
@ -173,9 +184,28 @@ class Node(unittest.TestCase):
|
|||||||
self.failUnless(isinstance(v, uri.SSKVerifierURI))
|
self.failUnless(isinstance(v, uri.SSKVerifierURI))
|
||||||
self.failUnlessEqual(n.get_repair_cap(), n._uri) # TODO: n.get_uri()
|
self.failUnlessEqual(n.get_repair_cap(), n._uri) # TODO: n.get_uri()
|
||||||
|
|
||||||
|
def test_mutable_filenode_equality(self):
|
||||||
|
client = FakeClient()
|
||||||
|
u = uri.WriteableSSKFileURI(b"\x00"*16, b"\x00"*32)
|
||||||
|
n = MutableFileNode(None, None, client.get_encoding_parameters(),
|
||||||
|
None).init_from_cap(u)
|
||||||
|
u2 = uri.WriteableSSKFileURI(b"\x01"*16, b"\x01"*32)
|
||||||
|
n2 = MutableFileNode(None, None, client.get_encoding_parameters(),
|
||||||
|
None).init_from_cap(u2)
|
||||||
|
n2b = MutableFileNode(None, None, client.get_encoding_parameters(),
|
||||||
|
None).init_from_cap(u2)
|
||||||
|
self.assertTrue(n2 == n2b)
|
||||||
|
self.assertFalse(n2 != n2b)
|
||||||
|
self.assertTrue(n2 != n)
|
||||||
|
self.assertTrue(n != n2)
|
||||||
|
self.assertFalse(n == n2)
|
||||||
|
self.assertTrue(n != 3)
|
||||||
|
self.assertFalse(n == 3)
|
||||||
|
|
||||||
|
|
||||||
class LiteralChecker(unittest.TestCase):
|
class LiteralChecker(unittest.TestCase):
|
||||||
def test_literal_filenode(self):
|
def test_literal_filenode(self):
|
||||||
DATA = "I am a short file."
|
DATA = b"I am a short file."
|
||||||
u = uri.LiteralFileURI(data=DATA)
|
u = uri.LiteralFileURI(data=DATA)
|
||||||
fn1 = LiteralFileNode(u)
|
fn1 = LiteralFileNode(u)
|
||||||
|
|
||||||
|
@ -1,3 +1,12 @@
|
|||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import division
|
||||||
|
from __future__ import print_function
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from future.utils import PY2
|
||||||
|
if PY2:
|
||||||
|
from future.builtins import filter, map, zip, ascii, chr, hex, input, next, oct, open, pow, round, super, bytes, dict, list, object, range, str, max, min # noqa: F401
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from twisted.internet import defer
|
from twisted.internet import defer
|
||||||
from twisted.trial import unittest
|
from twisted.trial import unittest
|
||||||
@ -18,7 +27,7 @@ from .common import (
|
|||||||
|
|
||||||
MiB = 1024*1024
|
MiB = 1024*1024
|
||||||
|
|
||||||
DATA = "I need help\n" * 1000
|
DATA = b"I need help\n" * 1000
|
||||||
|
|
||||||
class CHKUploadHelper_fake(offloaded.CHKUploadHelper):
|
class CHKUploadHelper_fake(offloaded.CHKUploadHelper):
|
||||||
def start_encrypted(self, eu):
|
def start_encrypted(self, eu):
|
||||||
@ -33,8 +42,8 @@ class CHKUploadHelper_fake(offloaded.CHKUploadHelper):
|
|||||||
"segment_size": segsize,
|
"segment_size": segsize,
|
||||||
"size": size,
|
"size": size,
|
||||||
}
|
}
|
||||||
ueb_hash = "fake"
|
ueb_hash = b"fake"
|
||||||
v = uri.CHKFileVerifierURI(self._storage_index, "x"*32,
|
v = uri.CHKFileVerifierURI(self._storage_index, b"x"*32,
|
||||||
needed_shares, total_shares, size)
|
needed_shares, total_shares, size)
|
||||||
_UR = upload.UploadResults
|
_UR = upload.UploadResults
|
||||||
ur = _UR(file_size=size,
|
ur = _UR(file_size=size,
|
||||||
@ -56,7 +65,7 @@ class CHKUploadHelper_fake(offloaded.CHKUploadHelper):
|
|||||||
|
|
||||||
class Helper_fake_upload(offloaded.Helper):
|
class Helper_fake_upload(offloaded.Helper):
|
||||||
def _make_chk_upload_helper(self, storage_index, lp):
|
def _make_chk_upload_helper(self, storage_index, lp):
|
||||||
si_s = si_b2a(storage_index)
|
si_s = str(si_b2a(storage_index), "utf-8")
|
||||||
incoming_file = os.path.join(self._chk_incoming, si_s)
|
incoming_file = os.path.join(self._chk_incoming, si_s)
|
||||||
encoding_file = os.path.join(self._chk_encoding, si_s)
|
encoding_file = os.path.join(self._chk_encoding, si_s)
|
||||||
uh = CHKUploadHelper_fake(storage_index, self,
|
uh = CHKUploadHelper_fake(storage_index, self,
|
||||||
@ -69,7 +78,7 @@ class Helper_fake_upload(offloaded.Helper):
|
|||||||
class Helper_already_uploaded(Helper_fake_upload):
|
class Helper_already_uploaded(Helper_fake_upload):
|
||||||
def _check_chk(self, storage_index, lp):
|
def _check_chk(self, storage_index, lp):
|
||||||
res = upload.HelperUploadResults()
|
res = upload.HelperUploadResults()
|
||||||
res.uri_extension_hash = hashutil.uri_extension_hash("")
|
res.uri_extension_hash = hashutil.uri_extension_hash(b"")
|
||||||
|
|
||||||
# we're pretending that the file they're trying to upload was already
|
# we're pretending that the file they're trying to upload was already
|
||||||
# present in the grid. We return some information about the file, so
|
# present in the grid. We return some information about the file, so
|
||||||
@ -127,14 +136,14 @@ class AssistedUpload(unittest.TestCase):
|
|||||||
lambda h: self.tub,
|
lambda h: self.tub,
|
||||||
EMPTY_CLIENT_CONFIG,
|
EMPTY_CLIENT_CONFIG,
|
||||||
)
|
)
|
||||||
self.s.secret_holder = client.SecretHolder("lease secret", "converge")
|
self.s.secret_holder = client.SecretHolder(b"lease secret", b"converge")
|
||||||
self.s.startService()
|
self.s.startService()
|
||||||
|
|
||||||
t.setServiceParent(self.s)
|
t.setServiceParent(self.s)
|
||||||
self.s.tub = t
|
self.s.tub = t
|
||||||
# we never actually use this for network traffic, so it can use a
|
# we never actually use this for network traffic, so it can use a
|
||||||
# bogus host/port
|
# bogus host/port
|
||||||
t.setLocation("bogus:1234")
|
t.setLocation(b"bogus:1234")
|
||||||
|
|
||||||
def setUpHelper(self, basedir, helper_class=Helper_fake_upload):
|
def setUpHelper(self, basedir, helper_class=Helper_fake_upload):
|
||||||
fileutil.make_dirs(basedir)
|
fileutil.make_dirs(basedir)
|
||||||
@ -162,11 +171,11 @@ class AssistedUpload(unittest.TestCase):
|
|||||||
def _ready(res):
|
def _ready(res):
|
||||||
assert u._helper
|
assert u._helper
|
||||||
|
|
||||||
return upload_data(u, DATA, convergence="some convergence string")
|
return upload_data(u, DATA, convergence=b"some convergence string")
|
||||||
d.addCallback(_ready)
|
d.addCallback(_ready)
|
||||||
def _uploaded(results):
|
def _uploaded(results):
|
||||||
the_uri = results.get_uri()
|
the_uri = results.get_uri()
|
||||||
assert "CHK" in the_uri
|
assert b"CHK" in the_uri
|
||||||
d.addCallback(_uploaded)
|
d.addCallback(_uploaded)
|
||||||
|
|
||||||
def _check_empty(res):
|
def _check_empty(res):
|
||||||
@ -195,11 +204,11 @@ class AssistedUpload(unittest.TestCase):
|
|||||||
# this must be a multiple of 'required_shares'==k
|
# this must be a multiple of 'required_shares'==k
|
||||||
segsize = mathutil.next_multiple(segsize, k)
|
segsize = mathutil.next_multiple(segsize, k)
|
||||||
|
|
||||||
key = hashutil.convergence_hash(k, n, segsize, DATA, "test convergence string")
|
key = hashutil.convergence_hash(k, n, segsize, DATA, b"test convergence string")
|
||||||
assert len(key) == 16
|
assert len(key) == 16
|
||||||
encryptor = aes.create_encryptor(key)
|
encryptor = aes.create_encryptor(key)
|
||||||
SI = hashutil.storage_index_hash(key)
|
SI = hashutil.storage_index_hash(key)
|
||||||
SI_s = si_b2a(SI)
|
SI_s = str(si_b2a(SI), "utf-8")
|
||||||
encfile = os.path.join(self.basedir, "CHK_encoding", SI_s)
|
encfile = os.path.join(self.basedir, "CHK_encoding", SI_s)
|
||||||
f = open(encfile, "wb")
|
f = open(encfile, "wb")
|
||||||
f.write(aes.encrypt_data(encryptor, DATA))
|
f.write(aes.encrypt_data(encryptor, DATA))
|
||||||
@ -212,11 +221,11 @@ class AssistedUpload(unittest.TestCase):
|
|||||||
|
|
||||||
def _ready(res):
|
def _ready(res):
|
||||||
assert u._helper
|
assert u._helper
|
||||||
return upload_data(u, DATA, convergence="test convergence string")
|
return upload_data(u, DATA, convergence=b"test convergence string")
|
||||||
d.addCallback(_ready)
|
d.addCallback(_ready)
|
||||||
def _uploaded(results):
|
def _uploaded(results):
|
||||||
the_uri = results.get_uri()
|
the_uri = results.get_uri()
|
||||||
assert "CHK" in the_uri
|
assert b"CHK" in the_uri
|
||||||
d.addCallback(_uploaded)
|
d.addCallback(_uploaded)
|
||||||
|
|
||||||
def _check_empty(res):
|
def _check_empty(res):
|
||||||
@ -239,11 +248,11 @@ class AssistedUpload(unittest.TestCase):
|
|||||||
def _ready(res):
|
def _ready(res):
|
||||||
assert u._helper
|
assert u._helper
|
||||||
|
|
||||||
return upload_data(u, DATA, convergence="some convergence string")
|
return upload_data(u, DATA, convergence=b"some convergence string")
|
||||||
d.addCallback(_ready)
|
d.addCallback(_ready)
|
||||||
def _uploaded(results):
|
def _uploaded(results):
|
||||||
the_uri = results.get_uri()
|
the_uri = results.get_uri()
|
||||||
assert "CHK" in the_uri
|
assert b"CHK" in the_uri
|
||||||
d.addCallback(_uploaded)
|
d.addCallback(_uploaded)
|
||||||
|
|
||||||
def _check_empty(res):
|
def _check_empty(res):
|
||||||
|
@ -1,3 +1,14 @@
|
|||||||
|
"""
|
||||||
|
This module has been ported to Python 3.
|
||||||
|
"""
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import division
|
||||||
|
from __future__ import print_function
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from future.utils import PY2
|
||||||
|
if PY2:
|
||||||
|
from future.builtins import filter, map, zip, ascii, chr, hex, input, next, oct, open, pow, round, super, bytes, dict, list, object, range, str, max, min # noqa: F401
|
||||||
|
|
||||||
import random
|
import random
|
||||||
|
|
||||||
@ -79,7 +90,7 @@ class TestShareFinder(unittest.TestCase):
|
|||||||
# ever", and then immediately tell them "oh, and here's
|
# ever", and then immediately tell them "oh, and here's
|
||||||
# another share", then you lose.
|
# another share", then you lose.
|
||||||
|
|
||||||
rcap = uri.CHKFileURI('a'*32, 'a'*32, 3, 99, 100)
|
rcap = uri.CHKFileURI(b'a'*32, b'a'*32, 3, 99, 100)
|
||||||
vcap = rcap.get_verify_cap()
|
vcap = rcap.get_verify_cap()
|
||||||
|
|
||||||
class MockBuckets(object):
|
class MockBuckets(object):
|
||||||
@ -88,8 +99,8 @@ class TestShareFinder(unittest.TestCase):
|
|||||||
class MockServer(object):
|
class MockServer(object):
|
||||||
def __init__(self, buckets):
|
def __init__(self, buckets):
|
||||||
self.version = {
|
self.version = {
|
||||||
'http://allmydata.org/tahoe/protocols/storage/v1': {
|
b'http://allmydata.org/tahoe/protocols/storage/v1': {
|
||||||
"tolerates-immutable-read-overrun": True
|
b"tolerates-immutable-read-overrun": True
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.buckets = buckets
|
self.buckets = buckets
|
||||||
@ -126,9 +137,9 @@ class TestShareFinder(unittest.TestCase):
|
|||||||
mockserver1 = MockServer({1: MockBuckets(), 2: MockBuckets()})
|
mockserver1 = MockServer({1: MockBuckets(), 2: MockBuckets()})
|
||||||
mockserver2 = MockServer({})
|
mockserver2 = MockServer({})
|
||||||
mockserver3 = MockServer({3: MockBuckets()})
|
mockserver3 = MockServer({3: MockBuckets()})
|
||||||
servers = [ NoNetworkServer("ms1", mockserver1),
|
servers = [ NoNetworkServer(b"ms1", mockserver1),
|
||||||
NoNetworkServer("ms2", mockserver2),
|
NoNetworkServer(b"ms2", mockserver2),
|
||||||
NoNetworkServer("ms3", mockserver3), ]
|
NoNetworkServer(b"ms3", mockserver3), ]
|
||||||
mockstoragebroker = MockStorageBroker(servers)
|
mockstoragebroker = MockStorageBroker(servers)
|
||||||
mockdownloadstatus = MockDownloadStatus()
|
mockdownloadstatus = MockDownloadStatus()
|
||||||
mocknode = MockNode(check_reneging=True, check_fetch_failed=True)
|
mocknode = MockNode(check_reneging=True, check_fetch_failed=True)
|
||||||
@ -155,7 +166,7 @@ class Test(GridTestMixin, unittest.TestCase, common.ShouldFailMixin):
|
|||||||
# Tests that need to test servers of happiness using this should
|
# Tests that need to test servers of happiness using this should
|
||||||
# set their own value for happy -- the default (7) breaks stuff.
|
# set their own value for happy -- the default (7) breaks stuff.
|
||||||
c1.encoding_params['happy'] = 1
|
c1.encoding_params['happy'] = 1
|
||||||
d = c1.upload(Data(TEST_DATA, convergence=""))
|
d = c1.upload(Data(TEST_DATA, convergence=b""))
|
||||||
def _after_upload(ur):
|
def _after_upload(ur):
|
||||||
self.uri = ur.get_uri()
|
self.uri = ur.get_uri()
|
||||||
self.filenode = self.g.clients[0].create_node_from_uri(ur.get_uri())
|
self.filenode = self.g.clients[0].create_node_from_uri(ur.get_uri())
|
||||||
@ -176,7 +187,7 @@ class Test(GridTestMixin, unittest.TestCase, common.ShouldFailMixin):
|
|||||||
return d
|
return d
|
||||||
|
|
||||||
def _shuffled(self, num_shnums):
|
def _shuffled(self, num_shnums):
|
||||||
shnums = range(10)
|
shnums = list(range(10))
|
||||||
random.shuffle(shnums)
|
random.shuffle(shnums)
|
||||||
return shnums[:num_shnums]
|
return shnums[:num_shnums]
|
||||||
|
|
||||||
|
@ -547,7 +547,7 @@ class Server(unittest.TestCase):
|
|||||||
already,writers = self.allocate(ss, b"disconnect", [0,1,2], 75, canary)
|
already,writers = self.allocate(ss, b"disconnect", [0,1,2], 75, canary)
|
||||||
self.failUnlessEqual(already, set())
|
self.failUnlessEqual(already, set())
|
||||||
self.failUnlessEqual(set(writers.keys()), set([0,1,2]))
|
self.failUnlessEqual(set(writers.keys()), set([0,1,2]))
|
||||||
for (f,args,kwargs) in canary.disconnectors.values():
|
for (f,args,kwargs) in list(canary.disconnectors.values()):
|
||||||
f(*args, **kwargs)
|
f(*args, **kwargs)
|
||||||
del already
|
del already
|
||||||
del writers
|
del writers
|
||||||
|
@ -11,7 +11,6 @@ from twisted.internet import defer
|
|||||||
from twisted.internet.defer import inlineCallbacks
|
from twisted.internet.defer import inlineCallbacks
|
||||||
from twisted.application import service
|
from twisted.application import service
|
||||||
|
|
||||||
import allmydata
|
|
||||||
from allmydata import client, uri
|
from allmydata import client, uri
|
||||||
from allmydata.introducer.server import create_introducer
|
from allmydata.introducer.server import create_introducer
|
||||||
from allmydata.storage.mutable import MutableShareFile
|
from allmydata.storage.mutable import MutableShareFile
|
||||||
@ -1629,7 +1628,6 @@ class SystemTest(SystemTestMixin, RunBinTahoeMixin, unittest.TestCase):
|
|||||||
for c in self.clients:
|
for c in self.clients:
|
||||||
c.encoding_params['happy'] = 1
|
c.encoding_params['happy'] = 1
|
||||||
d.addCallback(_new_happy_semantics)
|
d.addCallback(_new_happy_semantics)
|
||||||
d.addCallback(self._test_introweb)
|
|
||||||
d.addCallback(self.log, "starting publish")
|
d.addCallback(self.log, "starting publish")
|
||||||
d.addCallback(self._do_publish1)
|
d.addCallback(self._do_publish1)
|
||||||
d.addCallback(self._test_runner)
|
d.addCallback(self._test_runner)
|
||||||
@ -1668,58 +1666,6 @@ class SystemTest(SystemTestMixin, RunBinTahoeMixin, unittest.TestCase):
|
|||||||
d.addCallback(self._test_checker)
|
d.addCallback(self._test_checker)
|
||||||
return d
|
return d
|
||||||
|
|
||||||
def _test_introweb(self, res):
|
|
||||||
d = do_http("get", self.introweb_url)
|
|
||||||
def _check(res):
|
|
||||||
try:
|
|
||||||
self.failUnless("%s: %s" % (allmydata.__appname__, allmydata.__version__) in res)
|
|
||||||
verstr = str(allmydata.__version__)
|
|
||||||
|
|
||||||
# The Python "rational version numbering" convention
|
|
||||||
# disallows "-r$REV" but allows ".post$REV"
|
|
||||||
# instead. Eventually we'll probably move to
|
|
||||||
# that. When we do, this test won't go red:
|
|
||||||
ix = verstr.rfind('-r')
|
|
||||||
if ix != -1:
|
|
||||||
altverstr = verstr[:ix] + '.post' + verstr[ix+2:]
|
|
||||||
else:
|
|
||||||
ix = verstr.rfind('.post')
|
|
||||||
if ix != -1:
|
|
||||||
altverstr = verstr[:ix] + '-r' + verstr[ix+5:]
|
|
||||||
else:
|
|
||||||
altverstr = verstr
|
|
||||||
|
|
||||||
appverstr = "%s: %s" % (allmydata.__appname__, verstr)
|
|
||||||
newappverstr = "%s: %s" % (allmydata.__appname__, altverstr)
|
|
||||||
|
|
||||||
self.failUnless((appverstr in res) or (newappverstr in res), (appverstr, newappverstr, res))
|
|
||||||
self.failUnless("Announcement Summary: storage: 5" in res)
|
|
||||||
self.failUnless("Subscription Summary: storage: 5" in res)
|
|
||||||
self.failUnless("tahoe.css" in res)
|
|
||||||
except unittest.FailTest:
|
|
||||||
print()
|
|
||||||
print("GET %s output was:" % self.introweb_url)
|
|
||||||
print(res)
|
|
||||||
raise
|
|
||||||
d.addCallback(_check)
|
|
||||||
# make sure it serves the CSS too
|
|
||||||
d.addCallback(lambda res: do_http("get", self.introweb_url+"tahoe.css"))
|
|
||||||
d.addCallback(lambda res: do_http("get", self.introweb_url + "?t=json"))
|
|
||||||
def _check_json(res):
|
|
||||||
data = json.loads(res)
|
|
||||||
try:
|
|
||||||
self.failUnlessEqual(data["subscription_summary"],
|
|
||||||
{"storage": 5})
|
|
||||||
self.failUnlessEqual(data["announcement_summary"],
|
|
||||||
{"storage": 5})
|
|
||||||
except unittest.FailTest:
|
|
||||||
print()
|
|
||||||
print("GET %s?t=json output was:" % self.introweb_url)
|
|
||||||
print(res)
|
|
||||||
raise
|
|
||||||
d.addCallback(_check_json)
|
|
||||||
return d
|
|
||||||
|
|
||||||
def _do_publish1(self, res):
|
def _do_publish1(self, res):
|
||||||
ut = upload.Data(self.data, convergence=None)
|
ut = upload.Data(self.data, convergence=None)
|
||||||
c0 = self.clients[0]
|
c0 = self.clients[0]
|
||||||
|
@ -1,7 +1,20 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
Ported to Python 3.
|
||||||
|
"""
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import division
|
||||||
|
from __future__ import print_function
|
||||||
|
|
||||||
|
from future.utils import PY2
|
||||||
|
if PY2:
|
||||||
|
from future.builtins import filter, map, zip, ascii, chr, hex, input, next, oct, open, pow, round, super, bytes, dict, list, object, range, str, max, min # noqa: F401
|
||||||
|
|
||||||
import os, shutil
|
import os, shutil
|
||||||
from six.moves import cStringIO as StringIO
|
from io import BytesIO
|
||||||
|
|
||||||
from twisted.trial import unittest
|
from twisted.trial import unittest
|
||||||
from twisted.python.failure import Failure
|
from twisted.python.failure import Failure
|
||||||
from twisted.internet import defer, task
|
from twisted.internet import defer, task
|
||||||
@ -22,6 +35,7 @@ from allmydata.client import _Client
|
|||||||
from .common import (
|
from .common import (
|
||||||
EMPTY_CLIENT_CONFIG,
|
EMPTY_CLIENT_CONFIG,
|
||||||
)
|
)
|
||||||
|
from functools import reduce
|
||||||
|
|
||||||
|
|
||||||
MiB = 1024*1024
|
MiB = 1024*1024
|
||||||
@ -33,25 +47,25 @@ class Uploadable(unittest.TestCase):
|
|||||||
def shouldEqual(self, data, expected):
|
def shouldEqual(self, data, expected):
|
||||||
self.failUnless(isinstance(data, list))
|
self.failUnless(isinstance(data, list))
|
||||||
for e in data:
|
for e in data:
|
||||||
self.failUnless(isinstance(e, str))
|
self.failUnless(isinstance(e, bytes))
|
||||||
s = "".join(data)
|
s = b"".join(data)
|
||||||
self.failUnlessEqual(s, expected)
|
self.failUnlessEqual(s, expected)
|
||||||
|
|
||||||
def test_filehandle_random_key(self):
|
def test_filehandle_random_key(self):
|
||||||
return self._test_filehandle(convergence=None)
|
return self._test_filehandle(convergence=None)
|
||||||
|
|
||||||
def test_filehandle_convergent_encryption(self):
|
def test_filehandle_convergent_encryption(self):
|
||||||
return self._test_filehandle(convergence="some convergence string")
|
return self._test_filehandle(convergence=b"some convergence string")
|
||||||
|
|
||||||
def _test_filehandle(self, convergence):
|
def _test_filehandle(self, convergence):
|
||||||
s = StringIO("a"*41)
|
s = BytesIO(b"a"*41)
|
||||||
u = upload.FileHandle(s, convergence=convergence)
|
u = upload.FileHandle(s, convergence=convergence)
|
||||||
d = u.get_size()
|
d = u.get_size()
|
||||||
d.addCallback(self.failUnlessEqual, 41)
|
d.addCallback(self.failUnlessEqual, 41)
|
||||||
d.addCallback(lambda res: u.read(1))
|
d.addCallback(lambda res: u.read(1))
|
||||||
d.addCallback(self.shouldEqual, "a")
|
d.addCallback(self.shouldEqual, b"a")
|
||||||
d.addCallback(lambda res: u.read(80))
|
d.addCallback(lambda res: u.read(80))
|
||||||
d.addCallback(self.shouldEqual, "a"*40)
|
d.addCallback(self.shouldEqual, b"a"*40)
|
||||||
d.addCallback(lambda res: u.close()) # this doesn't close the filehandle
|
d.addCallback(lambda res: u.close()) # this doesn't close the filehandle
|
||||||
d.addCallback(lambda res: s.close()) # that privilege is reserved for us
|
d.addCallback(lambda res: s.close()) # that privilege is reserved for us
|
||||||
return d
|
return d
|
||||||
@ -60,28 +74,28 @@ class Uploadable(unittest.TestCase):
|
|||||||
basedir = "upload/Uploadable/test_filename"
|
basedir = "upload/Uploadable/test_filename"
|
||||||
os.makedirs(basedir)
|
os.makedirs(basedir)
|
||||||
fn = os.path.join(basedir, "file")
|
fn = os.path.join(basedir, "file")
|
||||||
f = open(fn, "w")
|
f = open(fn, "wb")
|
||||||
f.write("a"*41)
|
f.write(b"a"*41)
|
||||||
f.close()
|
f.close()
|
||||||
u = upload.FileName(fn, convergence=None)
|
u = upload.FileName(fn, convergence=None)
|
||||||
d = u.get_size()
|
d = u.get_size()
|
||||||
d.addCallback(self.failUnlessEqual, 41)
|
d.addCallback(self.failUnlessEqual, 41)
|
||||||
d.addCallback(lambda res: u.read(1))
|
d.addCallback(lambda res: u.read(1))
|
||||||
d.addCallback(self.shouldEqual, "a")
|
d.addCallback(self.shouldEqual, b"a")
|
||||||
d.addCallback(lambda res: u.read(80))
|
d.addCallback(lambda res: u.read(80))
|
||||||
d.addCallback(self.shouldEqual, "a"*40)
|
d.addCallback(self.shouldEqual, b"a"*40)
|
||||||
d.addCallback(lambda res: u.close())
|
d.addCallback(lambda res: u.close())
|
||||||
return d
|
return d
|
||||||
|
|
||||||
def test_data(self):
|
def test_data(self):
|
||||||
s = "a"*41
|
s = b"a"*41
|
||||||
u = upload.Data(s, convergence=None)
|
u = upload.Data(s, convergence=None)
|
||||||
d = u.get_size()
|
d = u.get_size()
|
||||||
d.addCallback(self.failUnlessEqual, 41)
|
d.addCallback(self.failUnlessEqual, 41)
|
||||||
d.addCallback(lambda res: u.read(1))
|
d.addCallback(lambda res: u.read(1))
|
||||||
d.addCallback(self.shouldEqual, "a")
|
d.addCallback(self.shouldEqual, b"a")
|
||||||
d.addCallback(lambda res: u.read(80))
|
d.addCallback(lambda res: u.read(80))
|
||||||
d.addCallback(self.shouldEqual, "a"*40)
|
d.addCallback(self.shouldEqual, b"a"*40)
|
||||||
d.addCallback(lambda res: u.close())
|
d.addCallback(lambda res: u.close())
|
||||||
return d
|
return d
|
||||||
|
|
||||||
@ -104,19 +118,19 @@ class FakeStorageServer(object):
|
|||||||
self._alloc_queries = 0
|
self._alloc_queries = 0
|
||||||
self._get_queries = 0
|
self._get_queries = 0
|
||||||
self.version = {
|
self.version = {
|
||||||
"http://allmydata.org/tahoe/protocols/storage/v1" :
|
b"http://allmydata.org/tahoe/protocols/storage/v1" :
|
||||||
{
|
{
|
||||||
"maximum-immutable-share-size": 2**32 - 1,
|
b"maximum-immutable-share-size": 2**32 - 1,
|
||||||
},
|
},
|
||||||
"application-version": str(allmydata.__full_version__),
|
b"application-version": bytes(allmydata.__full_version__, "ascii"),
|
||||||
}
|
}
|
||||||
if mode == "small":
|
if mode == "small":
|
||||||
self.version = {
|
self.version = {
|
||||||
"http://allmydata.org/tahoe/protocols/storage/v1" :
|
b"http://allmydata.org/tahoe/protocols/storage/v1" :
|
||||||
{
|
{
|
||||||
"maximum-immutable-share-size": 10,
|
b"maximum-immutable-share-size": 10,
|
||||||
},
|
},
|
||||||
"application-version": str(allmydata.__full_version__),
|
b"application-version": bytes(allmydata.__full_version__, "ascii"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -167,7 +181,7 @@ class FakeStorageServer(object):
|
|||||||
class FakeBucketWriter(object):
|
class FakeBucketWriter(object):
|
||||||
# a diagnostic version of storageserver.BucketWriter
|
# a diagnostic version of storageserver.BucketWriter
|
||||||
def __init__(self, size):
|
def __init__(self, size):
|
||||||
self.data = StringIO()
|
self.data = BytesIO()
|
||||||
self.closed = False
|
self.closed = False
|
||||||
self._size = size
|
self._size = size
|
||||||
|
|
||||||
@ -213,10 +227,10 @@ class FakeClient(object):
|
|||||||
def __init__(self, mode="good", num_servers=50, reactor=None):
|
def __init__(self, mode="good", num_servers=50, reactor=None):
|
||||||
self.num_servers = num_servers
|
self.num_servers = num_servers
|
||||||
self.encoding_params = self.DEFAULT_ENCODING_PARAMETERS.copy()
|
self.encoding_params = self.DEFAULT_ENCODING_PARAMETERS.copy()
|
||||||
if type(mode) is str:
|
if isinstance(mode, str):
|
||||||
mode = dict([i,mode] for i in range(num_servers))
|
mode = dict([i,mode] for i in range(num_servers))
|
||||||
servers = [
|
servers = [
|
||||||
("%20d" % fakeid, FakeStorageServer(mode[fakeid], reactor=reactor))
|
(b"%20d" % fakeid, FakeStorageServer(mode[fakeid], reactor=reactor))
|
||||||
for fakeid in range(self.num_servers)
|
for fakeid in range(self.num_servers)
|
||||||
]
|
]
|
||||||
self.storage_broker = StorageFarmBroker(
|
self.storage_broker = StorageFarmBroker(
|
||||||
@ -225,7 +239,7 @@ class FakeClient(object):
|
|||||||
node_config=EMPTY_CLIENT_CONFIG,
|
node_config=EMPTY_CLIENT_CONFIG,
|
||||||
)
|
)
|
||||||
for (serverid, rref) in servers:
|
for (serverid, rref) in servers:
|
||||||
ann = {"anonymous-storage-FURL": "pb://%s@nowhere/fake" % base32.b2a(serverid),
|
ann = {"anonymous-storage-FURL": b"pb://%s@nowhere/fake" % base32.b2a(serverid),
|
||||||
"permutation-seed-base32": base32.b2a(serverid) }
|
"permutation-seed-base32": base32.b2a(serverid) }
|
||||||
self.storage_broker.test_add_rref(serverid, rref, ann)
|
self.storage_broker.test_add_rref(serverid, rref, ann)
|
||||||
self.last_servers = [s[1] for s in servers]
|
self.last_servers = [s[1] for s in servers]
|
||||||
@ -236,7 +250,7 @@ class FakeClient(object):
|
|||||||
return self.encoding_params
|
return self.encoding_params
|
||||||
def get_storage_broker(self):
|
def get_storage_broker(self):
|
||||||
return self.storage_broker
|
return self.storage_broker
|
||||||
_secret_holder = client.SecretHolder("lease secret", "convergence secret")
|
_secret_holder = client.SecretHolder(b"lease secret", b"convergence secret")
|
||||||
|
|
||||||
class GotTooFarError(Exception):
|
class GotTooFarError(Exception):
|
||||||
pass
|
pass
|
||||||
@ -247,7 +261,7 @@ class GiganticUploadable(upload.FileHandle):
|
|||||||
self._fp = 0
|
self._fp = 0
|
||||||
|
|
||||||
def get_encryption_key(self):
|
def get_encryption_key(self):
|
||||||
return defer.succeed("\x00" * 16)
|
return defer.succeed(b"\x00" * 16)
|
||||||
def get_size(self):
|
def get_size(self):
|
||||||
return defer.succeed(self._size)
|
return defer.succeed(self._size)
|
||||||
def read(self, length):
|
def read(self, length):
|
||||||
@ -257,11 +271,11 @@ class GiganticUploadable(upload.FileHandle):
|
|||||||
if self._fp > 1000000:
|
if self._fp > 1000000:
|
||||||
# terminate the test early.
|
# terminate the test early.
|
||||||
raise GotTooFarError("we shouldn't be allowed to get this far")
|
raise GotTooFarError("we shouldn't be allowed to get this far")
|
||||||
return defer.succeed(["\x00" * length])
|
return defer.succeed([b"\x00" * length])
|
||||||
def close(self):
|
def close(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
DATA = """
|
DATA = b"""
|
||||||
Once upon a time, there was a beautiful princess named Buttercup. She lived
|
Once upon a time, there was a beautiful princess named Buttercup. She lived
|
||||||
in a magical land where every file was stored securely among millions of
|
in a magical land where every file was stored securely among millions of
|
||||||
machines, and nobody ever worried about their data being lost ever again.
|
machines, and nobody ever worried about their data being lost ever again.
|
||||||
@ -304,9 +318,9 @@ class GoodServer(unittest.TestCase, ShouldFailMixin, SetDEPMixin):
|
|||||||
def _check_large(self, newuri, size):
|
def _check_large(self, newuri, size):
|
||||||
u = uri.from_string(newuri)
|
u = uri.from_string(newuri)
|
||||||
self.failUnless(isinstance(u, uri.CHKFileURI))
|
self.failUnless(isinstance(u, uri.CHKFileURI))
|
||||||
self.failUnless(isinstance(u.get_storage_index(), str))
|
self.failUnless(isinstance(u.get_storage_index(), bytes))
|
||||||
self.failUnlessEqual(len(u.get_storage_index()), 16)
|
self.failUnlessEqual(len(u.get_storage_index()), 16)
|
||||||
self.failUnless(isinstance(u.key, str))
|
self.failUnless(isinstance(u.key, bytes))
|
||||||
self.failUnlessEqual(len(u.key), 16)
|
self.failUnlessEqual(len(u.key), 16)
|
||||||
self.failUnlessEqual(u.size, size)
|
self.failUnlessEqual(u.size, size)
|
||||||
|
|
||||||
@ -367,21 +381,21 @@ class GoodServer(unittest.TestCase, ShouldFailMixin, SetDEPMixin):
|
|||||||
|
|
||||||
def test_filehandle_zero(self):
|
def test_filehandle_zero(self):
|
||||||
data = self.get_data(SIZE_ZERO)
|
data = self.get_data(SIZE_ZERO)
|
||||||
d = upload_filehandle(self.u, StringIO(data))
|
d = upload_filehandle(self.u, BytesIO(data))
|
||||||
d.addCallback(extract_uri)
|
d.addCallback(extract_uri)
|
||||||
d.addCallback(self._check_small, SIZE_ZERO)
|
d.addCallback(self._check_small, SIZE_ZERO)
|
||||||
return d
|
return d
|
||||||
|
|
||||||
def test_filehandle_small(self):
|
def test_filehandle_small(self):
|
||||||
data = self.get_data(SIZE_SMALL)
|
data = self.get_data(SIZE_SMALL)
|
||||||
d = upload_filehandle(self.u, StringIO(data))
|
d = upload_filehandle(self.u, BytesIO(data))
|
||||||
d.addCallback(extract_uri)
|
d.addCallback(extract_uri)
|
||||||
d.addCallback(self._check_small, SIZE_SMALL)
|
d.addCallback(self._check_small, SIZE_SMALL)
|
||||||
return d
|
return d
|
||||||
|
|
||||||
def test_filehandle_large(self):
|
def test_filehandle_large(self):
|
||||||
data = self.get_data(SIZE_LARGE)
|
data = self.get_data(SIZE_LARGE)
|
||||||
d = upload_filehandle(self.u, StringIO(data))
|
d = upload_filehandle(self.u, BytesIO(data))
|
||||||
d.addCallback(extract_uri)
|
d.addCallback(extract_uri)
|
||||||
d.addCallback(self._check_large, SIZE_LARGE)
|
d.addCallback(self._check_large, SIZE_LARGE)
|
||||||
return d
|
return d
|
||||||
@ -429,9 +443,9 @@ class ServerErrors(unittest.TestCase, ShouldFailMixin, SetDEPMixin):
|
|||||||
def _check_large(self, newuri, size):
|
def _check_large(self, newuri, size):
|
||||||
u = uri.from_string(newuri)
|
u = uri.from_string(newuri)
|
||||||
self.failUnless(isinstance(u, uri.CHKFileURI))
|
self.failUnless(isinstance(u, uri.CHKFileURI))
|
||||||
self.failUnless(isinstance(u.get_storage_index(), str))
|
self.failUnless(isinstance(u.get_storage_index(), bytes))
|
||||||
self.failUnlessEqual(len(u.get_storage_index()), 16)
|
self.failUnlessEqual(len(u.get_storage_index()), 16)
|
||||||
self.failUnless(isinstance(u.key, str))
|
self.failUnless(isinstance(u.key, bytes))
|
||||||
self.failUnlessEqual(len(u.key), 16)
|
self.failUnlessEqual(len(u.key), 16)
|
||||||
self.failUnlessEqual(u.size, size)
|
self.failUnlessEqual(u.size, size)
|
||||||
|
|
||||||
@ -599,9 +613,9 @@ class ServerSelection(unittest.TestCase):
|
|||||||
def _check_large(self, newuri, size):
|
def _check_large(self, newuri, size):
|
||||||
u = uri.from_string(newuri)
|
u = uri.from_string(newuri)
|
||||||
self.failUnless(isinstance(u, uri.CHKFileURI))
|
self.failUnless(isinstance(u, uri.CHKFileURI))
|
||||||
self.failUnless(isinstance(u.get_storage_index(), str))
|
self.failUnless(isinstance(u.get_storage_index(), bytes))
|
||||||
self.failUnlessEqual(len(u.get_storage_index()), 16)
|
self.failUnlessEqual(len(u.get_storage_index()), 16)
|
||||||
self.failUnless(isinstance(u.key, str))
|
self.failUnless(isinstance(u.key, bytes))
|
||||||
self.failUnlessEqual(len(u.key), 16)
|
self.failUnlessEqual(len(u.key), 16)
|
||||||
self.failUnlessEqual(u.size, size)
|
self.failUnlessEqual(u.size, size)
|
||||||
|
|
||||||
@ -764,40 +778,40 @@ class ServerSelection(unittest.TestCase):
|
|||||||
|
|
||||||
class StorageIndex(unittest.TestCase):
|
class StorageIndex(unittest.TestCase):
|
||||||
def test_params_must_matter(self):
|
def test_params_must_matter(self):
|
||||||
DATA = "I am some data"
|
DATA = b"I am some data"
|
||||||
PARAMS = _Client.DEFAULT_ENCODING_PARAMETERS
|
PARAMS = _Client.DEFAULT_ENCODING_PARAMETERS
|
||||||
|
|
||||||
u = upload.Data(DATA, convergence="")
|
u = upload.Data(DATA, convergence=b"")
|
||||||
u.set_default_encoding_parameters(PARAMS)
|
u.set_default_encoding_parameters(PARAMS)
|
||||||
eu = upload.EncryptAnUploadable(u)
|
eu = upload.EncryptAnUploadable(u)
|
||||||
d1 = eu.get_storage_index()
|
d1 = eu.get_storage_index()
|
||||||
|
|
||||||
# CHK means the same data should encrypt the same way
|
# CHK means the same data should encrypt the same way
|
||||||
u = upload.Data(DATA, convergence="")
|
u = upload.Data(DATA, convergence=b"")
|
||||||
u.set_default_encoding_parameters(PARAMS)
|
u.set_default_encoding_parameters(PARAMS)
|
||||||
eu = upload.EncryptAnUploadable(u)
|
eu = upload.EncryptAnUploadable(u)
|
||||||
d1a = eu.get_storage_index()
|
d1a = eu.get_storage_index()
|
||||||
|
|
||||||
# but if we use a different convergence string it should be different
|
# but if we use a different convergence string it should be different
|
||||||
u = upload.Data(DATA, convergence="wheee!")
|
u = upload.Data(DATA, convergence=b"wheee!")
|
||||||
u.set_default_encoding_parameters(PARAMS)
|
u.set_default_encoding_parameters(PARAMS)
|
||||||
eu = upload.EncryptAnUploadable(u)
|
eu = upload.EncryptAnUploadable(u)
|
||||||
d1salt1 = eu.get_storage_index()
|
d1salt1 = eu.get_storage_index()
|
||||||
|
|
||||||
# and if we add yet a different convergence it should be different again
|
# and if we add yet a different convergence it should be different again
|
||||||
u = upload.Data(DATA, convergence="NOT wheee!")
|
u = upload.Data(DATA, convergence=b"NOT wheee!")
|
||||||
u.set_default_encoding_parameters(PARAMS)
|
u.set_default_encoding_parameters(PARAMS)
|
||||||
eu = upload.EncryptAnUploadable(u)
|
eu = upload.EncryptAnUploadable(u)
|
||||||
d1salt2 = eu.get_storage_index()
|
d1salt2 = eu.get_storage_index()
|
||||||
|
|
||||||
# and if we use the first string again it should be the same as last time
|
# and if we use the first string again it should be the same as last time
|
||||||
u = upload.Data(DATA, convergence="wheee!")
|
u = upload.Data(DATA, convergence=b"wheee!")
|
||||||
u.set_default_encoding_parameters(PARAMS)
|
u.set_default_encoding_parameters(PARAMS)
|
||||||
eu = upload.EncryptAnUploadable(u)
|
eu = upload.EncryptAnUploadable(u)
|
||||||
d1salt1a = eu.get_storage_index()
|
d1salt1a = eu.get_storage_index()
|
||||||
|
|
||||||
# and if we change the encoding parameters, it should be different (from the same convergence string with different encoding parameters)
|
# and if we change the encoding parameters, it should be different (from the same convergence string with different encoding parameters)
|
||||||
u = upload.Data(DATA, convergence="")
|
u = upload.Data(DATA, convergence=b"")
|
||||||
u.set_default_encoding_parameters(PARAMS)
|
u.set_default_encoding_parameters(PARAMS)
|
||||||
u.encoding_param_k = u.default_encoding_param_k + 1
|
u.encoding_param_k = u.default_encoding_param_k + 1
|
||||||
eu = upload.EncryptAnUploadable(u)
|
eu = upload.EncryptAnUploadable(u)
|
||||||
@ -838,10 +852,10 @@ def combinations(iterable, r):
|
|||||||
n = len(pool)
|
n = len(pool)
|
||||||
if r > n:
|
if r > n:
|
||||||
return
|
return
|
||||||
indices = range(r)
|
indices = list(range(r))
|
||||||
yield tuple(pool[i] for i in indices)
|
yield tuple(pool[i] for i in indices)
|
||||||
while True:
|
while True:
|
||||||
for i in reversed(range(r)):
|
for i in reversed(list(range(r))):
|
||||||
if indices[i] != i + n - r:
|
if indices[i] != i + n - r:
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
@ -855,7 +869,7 @@ def is_happy_enough(servertoshnums, h, k):
|
|||||||
""" I calculate whether servertoshnums achieves happiness level h. I do this with a naïve "brute force search" approach. (See src/allmydata/util/happinessutil.py for a better algorithm.) """
|
""" I calculate whether servertoshnums achieves happiness level h. I do this with a naïve "brute force search" approach. (See src/allmydata/util/happinessutil.py for a better algorithm.) """
|
||||||
if len(servertoshnums) < h:
|
if len(servertoshnums) < h:
|
||||||
return False
|
return False
|
||||||
for happysetcombo in combinations(servertoshnums.iterkeys(), h):
|
for happysetcombo in combinations(iter(servertoshnums.keys()), h):
|
||||||
for subsetcombo in combinations(happysetcombo, k):
|
for subsetcombo in combinations(happysetcombo, k):
|
||||||
shnums = reduce(set.union, [ servertoshnums[s] for s in subsetcombo ])
|
shnums = reduce(set.union, [ servertoshnums[s] for s in subsetcombo ])
|
||||||
if len(shnums) < k:
|
if len(shnums) < k:
|
||||||
@ -886,7 +900,7 @@ class EncodingParameters(GridTestMixin, unittest.TestCase, SetDEPMixin,
|
|||||||
assert self.g, "I tried to find a grid at self.g, but failed"
|
assert self.g, "I tried to find a grid at self.g, but failed"
|
||||||
servertoshnums = {} # k: server, v: set(shnum)
|
servertoshnums = {} # k: server, v: set(shnum)
|
||||||
|
|
||||||
for i, c in self.g.servers_by_number.iteritems():
|
for i, c in self.g.servers_by_number.items():
|
||||||
for (dirp, dirns, fns) in os.walk(c.sharedir):
|
for (dirp, dirns, fns) in os.walk(c.sharedir):
|
||||||
for fn in fns:
|
for fn in fns:
|
||||||
try:
|
try:
|
||||||
@ -909,7 +923,7 @@ class EncodingParameters(GridTestMixin, unittest.TestCase, SetDEPMixin,
|
|||||||
assert self.g, "I tried to find a grid at self.g, but failed"
|
assert self.g, "I tried to find a grid at self.g, but failed"
|
||||||
broker = self.g.clients[0].storage_broker
|
broker = self.g.clients[0].storage_broker
|
||||||
sh = self.g.clients[0]._secret_holder
|
sh = self.g.clients[0]._secret_holder
|
||||||
data = upload.Data("data" * 10000, convergence="")
|
data = upload.Data(b"data" * 10000, convergence=b"")
|
||||||
data.set_default_encoding_parameters({'k': 3, 'happy': 4, 'n': 10})
|
data.set_default_encoding_parameters({'k': 3, 'happy': 4, 'n': 10})
|
||||||
uploadable = upload.EncryptAnUploadable(data)
|
uploadable = upload.EncryptAnUploadable(data)
|
||||||
encoder = encode.Encoder()
|
encoder = encode.Encoder()
|
||||||
@ -926,9 +940,9 @@ class EncodingParameters(GridTestMixin, unittest.TestCase, SetDEPMixin,
|
|||||||
def _have_shareholders(upload_trackers_and_already_servers):
|
def _have_shareholders(upload_trackers_and_already_servers):
|
||||||
(upload_trackers, already_servers) = upload_trackers_and_already_servers
|
(upload_trackers, already_servers) = upload_trackers_and_already_servers
|
||||||
assert servers_to_break <= len(upload_trackers)
|
assert servers_to_break <= len(upload_trackers)
|
||||||
for index in xrange(servers_to_break):
|
for index in range(servers_to_break):
|
||||||
tracker = list(upload_trackers)[index]
|
tracker = list(upload_trackers)[index]
|
||||||
for share in tracker.buckets.keys():
|
for share in list(tracker.buckets.keys()):
|
||||||
tracker.buckets[share].abort()
|
tracker.buckets[share].abort()
|
||||||
buckets = {}
|
buckets = {}
|
||||||
servermap = already_servers.copy()
|
servermap = already_servers.copy()
|
||||||
@ -1002,7 +1016,7 @@ class EncodingParameters(GridTestMixin, unittest.TestCase, SetDEPMixin,
|
|||||||
if "n" in kwargs and "k" in kwargs:
|
if "n" in kwargs and "k" in kwargs:
|
||||||
client.encoding_params['k'] = kwargs['k']
|
client.encoding_params['k'] = kwargs['k']
|
||||||
client.encoding_params['n'] = kwargs['n']
|
client.encoding_params['n'] = kwargs['n']
|
||||||
data = upload.Data("data" * 10000, convergence="")
|
data = upload.Data(b"data" * 10000, convergence=b"")
|
||||||
self.data = data
|
self.data = data
|
||||||
d = client.upload(data)
|
d = client.upload(data)
|
||||||
def _store_uri(ur):
|
def _store_uri(ur):
|
||||||
@ -1021,8 +1035,8 @@ class EncodingParameters(GridTestMixin, unittest.TestCase, SetDEPMixin,
|
|||||||
self.set_up_grid(client_config_hooks=hooks)
|
self.set_up_grid(client_config_hooks=hooks)
|
||||||
c0 = self.g.clients[0]
|
c0 = self.g.clients[0]
|
||||||
|
|
||||||
DATA = "data" * 100
|
DATA = b"data" * 100
|
||||||
u = upload.Data(DATA, convergence="")
|
u = upload.Data(DATA, convergence=b"")
|
||||||
d = c0.upload(u)
|
d = c0.upload(u)
|
||||||
d.addCallback(lambda ur: c0.create_node_from_uri(ur.get_uri()))
|
d.addCallback(lambda ur: c0.create_node_from_uri(ur.get_uri()))
|
||||||
m = monitor.Monitor()
|
m = monitor.Monitor()
|
||||||
@ -1045,7 +1059,7 @@ class EncodingParameters(GridTestMixin, unittest.TestCase, SetDEPMixin,
|
|||||||
|
|
||||||
def test_happy_semantics(self):
|
def test_happy_semantics(self):
|
||||||
self._setUp(2)
|
self._setUp(2)
|
||||||
DATA = upload.Data("kittens" * 10000, convergence="")
|
DATA = upload.Data(b"kittens" * 10000, convergence=b"")
|
||||||
# These parameters are unsatisfiable with only 2 servers.
|
# These parameters are unsatisfiable with only 2 servers.
|
||||||
self.set_encoding_parameters(k=3, happy=5, n=10)
|
self.set_encoding_parameters(k=3, happy=5, n=10)
|
||||||
d = self.shouldFail(UploadUnhappinessError, "test_happy_semantics",
|
d = self.shouldFail(UploadUnhappinessError, "test_happy_semantics",
|
||||||
@ -1077,7 +1091,7 @@ class EncodingParameters(GridTestMixin, unittest.TestCase, SetDEPMixin,
|
|||||||
self.basedir = "upload/EncodingParameters/aborted_shares"
|
self.basedir = "upload/EncodingParameters/aborted_shares"
|
||||||
self.set_up_grid(num_servers=4)
|
self.set_up_grid(num_servers=4)
|
||||||
c = self.g.clients[0]
|
c = self.g.clients[0]
|
||||||
DATA = upload.Data(100 * "kittens", convergence="")
|
DATA = upload.Data(100 * b"kittens", convergence=b"")
|
||||||
# These parameters are unsatisfiable with only 4 servers, but should
|
# These parameters are unsatisfiable with only 4 servers, but should
|
||||||
# work with 5, as long as the original 4 are not stuck in the open
|
# work with 5, as long as the original 4 are not stuck in the open
|
||||||
# BucketWriter state (open() but not
|
# BucketWriter state (open() but not
|
||||||
@ -1155,8 +1169,8 @@ class EncodingParameters(GridTestMixin, unittest.TestCase, SetDEPMixin,
|
|||||||
"We were asked to place shares on at "
|
"We were asked to place shares on at "
|
||||||
"least 4 servers such that any 3 of them have "
|
"least 4 servers such that any 3 of them have "
|
||||||
"enough shares to recover the file",
|
"enough shares to recover the file",
|
||||||
client.upload, upload.Data("data" * 10000,
|
client.upload, upload.Data(b"data" * 10000,
|
||||||
convergence="")))
|
convergence=b"")))
|
||||||
|
|
||||||
# Do comment:52, but like this:
|
# Do comment:52, but like this:
|
||||||
# server 2: empty
|
# server 2: empty
|
||||||
@ -1188,8 +1202,8 @@ class EncodingParameters(GridTestMixin, unittest.TestCase, SetDEPMixin,
|
|||||||
"that any 3 of them have enough shares to recover "
|
"that any 3 of them have enough shares to recover "
|
||||||
"the file, but we were asked to place shares on "
|
"the file, but we were asked to place shares on "
|
||||||
"at least 4 such servers.",
|
"at least 4 such servers.",
|
||||||
client.upload, upload.Data("data" * 10000,
|
client.upload, upload.Data(b"data" * 10000,
|
||||||
convergence="")))
|
convergence=b"")))
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
|
||||||
@ -1230,7 +1244,7 @@ class EncodingParameters(GridTestMixin, unittest.TestCase, SetDEPMixin,
|
|||||||
return client
|
return client
|
||||||
d.addCallback(_reset_encoding_parameters)
|
d.addCallback(_reset_encoding_parameters)
|
||||||
d.addCallback(lambda client:
|
d.addCallback(lambda client:
|
||||||
client.upload(upload.Data("data" * 10000, convergence="")))
|
client.upload(upload.Data(b"data" * 10000, convergence=b"")))
|
||||||
d.addCallback(lambda ign:
|
d.addCallback(lambda ign:
|
||||||
self.failUnless(self._has_happy_share_distribution()))
|
self.failUnless(self._has_happy_share_distribution()))
|
||||||
|
|
||||||
@ -1259,7 +1273,7 @@ class EncodingParameters(GridTestMixin, unittest.TestCase, SetDEPMixin,
|
|||||||
self._add_server_with_share(server_number=1, share_number=2))
|
self._add_server_with_share(server_number=1, share_number=2))
|
||||||
# Copy all of the other shares to server number 2
|
# Copy all of the other shares to server number 2
|
||||||
def _copy_shares(ign):
|
def _copy_shares(ign):
|
||||||
for i in xrange(0, 10):
|
for i in range(0, 10):
|
||||||
self._copy_share_to_server(i, 2)
|
self._copy_share_to_server(i, 2)
|
||||||
d.addCallback(_copy_shares)
|
d.addCallback(_copy_shares)
|
||||||
# Remove the first server, and add a placeholder with share 0
|
# Remove the first server, and add a placeholder with share 0
|
||||||
@ -1270,7 +1284,7 @@ class EncodingParameters(GridTestMixin, unittest.TestCase, SetDEPMixin,
|
|||||||
# Now try uploading.
|
# Now try uploading.
|
||||||
d.addCallback(_reset_encoding_parameters)
|
d.addCallback(_reset_encoding_parameters)
|
||||||
d.addCallback(lambda client:
|
d.addCallback(lambda client:
|
||||||
client.upload(upload.Data("data" * 10000, convergence="")))
|
client.upload(upload.Data(b"data" * 10000, convergence=b"")))
|
||||||
d.addCallback(lambda ign:
|
d.addCallback(lambda ign:
|
||||||
self.failUnless(self._has_happy_share_distribution()))
|
self.failUnless(self._has_happy_share_distribution()))
|
||||||
|
|
||||||
@ -1299,7 +1313,7 @@ class EncodingParameters(GridTestMixin, unittest.TestCase, SetDEPMixin,
|
|||||||
self.g.remove_server(self.g.servers_by_number[0].my_nodeid))
|
self.g.remove_server(self.g.servers_by_number[0].my_nodeid))
|
||||||
d.addCallback(_reset_encoding_parameters)
|
d.addCallback(_reset_encoding_parameters)
|
||||||
d.addCallback(lambda client:
|
d.addCallback(lambda client:
|
||||||
client.upload(upload.Data("data" * 10000, convergence="")))
|
client.upload(upload.Data(b"data" * 10000, convergence=b"")))
|
||||||
# Make sure that only as many shares as necessary to satisfy
|
# Make sure that only as many shares as necessary to satisfy
|
||||||
# servers of happiness were pushed.
|
# servers of happiness were pushed.
|
||||||
d.addCallback(lambda results:
|
d.addCallback(lambda results:
|
||||||
@ -1330,7 +1344,7 @@ class EncodingParameters(GridTestMixin, unittest.TestCase, SetDEPMixin,
|
|||||||
|
|
||||||
d.addCallback(_setup)
|
d.addCallback(_setup)
|
||||||
d.addCallback(lambda client:
|
d.addCallback(lambda client:
|
||||||
client.upload(upload.Data("data" * 10000, convergence="")))
|
client.upload(upload.Data(b"data" * 10000, convergence=b"")))
|
||||||
d.addCallback(lambda ign:
|
d.addCallback(lambda ign:
|
||||||
self.failUnless(self._has_happy_share_distribution()))
|
self.failUnless(self._has_happy_share_distribution()))
|
||||||
return d
|
return d
|
||||||
@ -1353,7 +1367,7 @@ class EncodingParameters(GridTestMixin, unittest.TestCase, SetDEPMixin,
|
|||||||
readonly=True))
|
readonly=True))
|
||||||
# Copy all of the other shares to server number 2
|
# Copy all of the other shares to server number 2
|
||||||
def _copy_shares(ign):
|
def _copy_shares(ign):
|
||||||
for i in xrange(1, 10):
|
for i in range(1, 10):
|
||||||
self._copy_share_to_server(i, 2)
|
self._copy_share_to_server(i, 2)
|
||||||
d.addCallback(_copy_shares)
|
d.addCallback(_copy_shares)
|
||||||
# Remove server 0, and add another in its place
|
# Remove server 0, and add another in its place
|
||||||
@ -1368,7 +1382,7 @@ class EncodingParameters(GridTestMixin, unittest.TestCase, SetDEPMixin,
|
|||||||
return client
|
return client
|
||||||
d.addCallback(_reset_encoding_parameters)
|
d.addCallback(_reset_encoding_parameters)
|
||||||
d.addCallback(lambda client:
|
d.addCallback(lambda client:
|
||||||
client.upload(upload.Data("data" * 10000, convergence="")))
|
client.upload(upload.Data(b"data" * 10000, convergence=b"")))
|
||||||
d.addCallback(lambda ign:
|
d.addCallback(lambda ign:
|
||||||
self.failUnless(self._has_happy_share_distribution()))
|
self.failUnless(self._has_happy_share_distribution()))
|
||||||
return d
|
return d
|
||||||
@ -1396,7 +1410,7 @@ class EncodingParameters(GridTestMixin, unittest.TestCase, SetDEPMixin,
|
|||||||
self._add_server_with_share(server_number=2, share_number=0,
|
self._add_server_with_share(server_number=2, share_number=0,
|
||||||
readonly=True))
|
readonly=True))
|
||||||
def _copy_shares(ign):
|
def _copy_shares(ign):
|
||||||
for i in xrange(1, 10):
|
for i in range(1, 10):
|
||||||
self._copy_share_to_server(i, 2)
|
self._copy_share_to_server(i, 2)
|
||||||
d.addCallback(_copy_shares)
|
d.addCallback(_copy_shares)
|
||||||
d.addCallback(lambda ign:
|
d.addCallback(lambda ign:
|
||||||
@ -1407,7 +1421,7 @@ class EncodingParameters(GridTestMixin, unittest.TestCase, SetDEPMixin,
|
|||||||
return client
|
return client
|
||||||
d.addCallback(_reset_encoding_parameters)
|
d.addCallback(_reset_encoding_parameters)
|
||||||
d.addCallback(lambda client:
|
d.addCallback(lambda client:
|
||||||
client.upload(upload.Data("data" * 10000, convergence="")))
|
client.upload(upload.Data(b"data" * 10000, convergence=b"")))
|
||||||
d.addCallback(lambda ign:
|
d.addCallback(lambda ign:
|
||||||
self.failUnless(self._has_happy_share_distribution()))
|
self.failUnless(self._has_happy_share_distribution()))
|
||||||
return d
|
return d
|
||||||
@ -1512,7 +1526,7 @@ class EncodingParameters(GridTestMixin, unittest.TestCase, SetDEPMixin,
|
|||||||
d.addCallback(lambda ign:
|
d.addCallback(lambda ign:
|
||||||
self._add_server(4))
|
self._add_server(4))
|
||||||
def _copy_shares(ign):
|
def _copy_shares(ign):
|
||||||
for i in xrange(1, 10):
|
for i in range(1, 10):
|
||||||
self._copy_share_to_server(i, 1)
|
self._copy_share_to_server(i, 1)
|
||||||
d.addCallback(_copy_shares)
|
d.addCallback(_copy_shares)
|
||||||
d.addCallback(lambda ign:
|
d.addCallback(lambda ign:
|
||||||
@ -1523,7 +1537,7 @@ class EncodingParameters(GridTestMixin, unittest.TestCase, SetDEPMixin,
|
|||||||
return client
|
return client
|
||||||
d.addCallback(_prepare_client)
|
d.addCallback(_prepare_client)
|
||||||
d.addCallback(lambda client:
|
d.addCallback(lambda client:
|
||||||
client.upload(upload.Data("data" * 10000, convergence="")))
|
client.upload(upload.Data(b"data" * 10000, convergence=b"")))
|
||||||
d.addCallback(lambda ign:
|
d.addCallback(lambda ign:
|
||||||
self.failUnless(self._has_happy_share_distribution()))
|
self.failUnless(self._has_happy_share_distribution()))
|
||||||
return d
|
return d
|
||||||
@ -1536,7 +1550,7 @@ class EncodingParameters(GridTestMixin, unittest.TestCase, SetDEPMixin,
|
|||||||
self.basedir = self.mktemp()
|
self.basedir = self.mktemp()
|
||||||
d = self._setup_and_upload()
|
d = self._setup_and_upload()
|
||||||
def _setup(ign):
|
def _setup(ign):
|
||||||
for i in xrange(1, 11):
|
for i in range(1, 11):
|
||||||
self._add_server(server_number=i)
|
self._add_server(server_number=i)
|
||||||
self.g.remove_server(self.g.servers_by_number[0].my_nodeid)
|
self.g.remove_server(self.g.servers_by_number[0].my_nodeid)
|
||||||
c = self.g.clients[0]
|
c = self.g.clients[0]
|
||||||
@ -1550,8 +1564,8 @@ class EncodingParameters(GridTestMixin, unittest.TestCase, SetDEPMixin,
|
|||||||
d.addCallback(lambda c:
|
d.addCallback(lambda c:
|
||||||
self.shouldFail(UploadUnhappinessError, "test_query_counting",
|
self.shouldFail(UploadUnhappinessError, "test_query_counting",
|
||||||
"0 queries placed some shares",
|
"0 queries placed some shares",
|
||||||
c.upload, upload.Data("data" * 10000,
|
c.upload, upload.Data(b"data" * 10000,
|
||||||
convergence="")))
|
convergence=b"")))
|
||||||
# Now try with some readonly servers. We want to make sure that
|
# Now try with some readonly servers. We want to make sure that
|
||||||
# the readonly server share discovery phase is counted correctly.
|
# the readonly server share discovery phase is counted correctly.
|
||||||
def _reset(ign):
|
def _reset(ign):
|
||||||
@ -1561,7 +1575,7 @@ class EncodingParameters(GridTestMixin, unittest.TestCase, SetDEPMixin,
|
|||||||
d.addCallback(lambda ign:
|
d.addCallback(lambda ign:
|
||||||
self._setup_and_upload())
|
self._setup_and_upload())
|
||||||
def _then(ign):
|
def _then(ign):
|
||||||
for i in xrange(1, 11):
|
for i in range(1, 11):
|
||||||
self._add_server(server_number=i)
|
self._add_server(server_number=i)
|
||||||
self._add_server(server_number=11, readonly=True)
|
self._add_server(server_number=11, readonly=True)
|
||||||
self._add_server(server_number=12, readonly=True)
|
self._add_server(server_number=12, readonly=True)
|
||||||
@ -1574,8 +1588,8 @@ class EncodingParameters(GridTestMixin, unittest.TestCase, SetDEPMixin,
|
|||||||
self.shouldFail(UploadUnhappinessError, "test_query_counting",
|
self.shouldFail(UploadUnhappinessError, "test_query_counting",
|
||||||
"4 placed none (of which 4 placed none due to "
|
"4 placed none (of which 4 placed none due to "
|
||||||
"the server being full",
|
"the server being full",
|
||||||
c.upload, upload.Data("data" * 10000,
|
c.upload, upload.Data(b"data" * 10000,
|
||||||
convergence="")))
|
convergence=b"")))
|
||||||
# Now try the case where the upload process finds a bunch of the
|
# Now try the case where the upload process finds a bunch of the
|
||||||
# shares that it wants to place on the first server, including
|
# shares that it wants to place on the first server, including
|
||||||
# the one that it wanted to allocate there. Though no shares will
|
# the one that it wanted to allocate there. Though no shares will
|
||||||
@ -1587,11 +1601,11 @@ class EncodingParameters(GridTestMixin, unittest.TestCase, SetDEPMixin,
|
|||||||
self._setup_and_upload())
|
self._setup_and_upload())
|
||||||
|
|
||||||
def _next(ign):
|
def _next(ign):
|
||||||
for i in xrange(1, 11):
|
for i in range(1, 11):
|
||||||
self._add_server(server_number=i)
|
self._add_server(server_number=i)
|
||||||
# Copy all of the shares to server 9, since that will be
|
# Copy all of the shares to server 9, since that will be
|
||||||
# the first one that the selector sees.
|
# the first one that the selector sees.
|
||||||
for i in xrange(10):
|
for i in range(10):
|
||||||
self._copy_share_to_server(i, 9)
|
self._copy_share_to_server(i, 9)
|
||||||
# Remove server 0, and its contents
|
# Remove server 0, and its contents
|
||||||
self.g.remove_server(self.g.servers_by_number[0].my_nodeid)
|
self.g.remove_server(self.g.servers_by_number[0].my_nodeid)
|
||||||
@ -1603,8 +1617,8 @@ class EncodingParameters(GridTestMixin, unittest.TestCase, SetDEPMixin,
|
|||||||
d.addCallback(lambda c:
|
d.addCallback(lambda c:
|
||||||
self.shouldFail(UploadUnhappinessError, "test_query_counting",
|
self.shouldFail(UploadUnhappinessError, "test_query_counting",
|
||||||
"0 queries placed some shares",
|
"0 queries placed some shares",
|
||||||
c.upload, upload.Data("data" * 10000,
|
c.upload, upload.Data(b"data" * 10000,
|
||||||
convergence="")))
|
convergence=b"")))
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
|
||||||
@ -1612,7 +1626,7 @@ class EncodingParameters(GridTestMixin, unittest.TestCase, SetDEPMixin,
|
|||||||
self.basedir = self.mktemp()
|
self.basedir = self.mktemp()
|
||||||
d = self._setup_and_upload()
|
d = self._setup_and_upload()
|
||||||
def _then(ign):
|
def _then(ign):
|
||||||
for i in xrange(1, 11):
|
for i in range(1, 11):
|
||||||
self._add_server(server_number=i, readonly=True)
|
self._add_server(server_number=i, readonly=True)
|
||||||
self.g.remove_server(self.g.servers_by_number[0].my_nodeid)
|
self.g.remove_server(self.g.servers_by_number[0].my_nodeid)
|
||||||
c = self.g.clients[0]
|
c = self.g.clients[0]
|
||||||
@ -1626,7 +1640,7 @@ class EncodingParameters(GridTestMixin, unittest.TestCase, SetDEPMixin,
|
|||||||
"test_upper_limit_on_readonly_queries",
|
"test_upper_limit_on_readonly_queries",
|
||||||
"sent 8 queries to 8 servers",
|
"sent 8 queries to 8 servers",
|
||||||
client.upload,
|
client.upload,
|
||||||
upload.Data('data' * 10000, convergence="")))
|
upload.Data(b'data' * 10000, convergence=b"")))
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
|
||||||
@ -1668,7 +1682,7 @@ class EncodingParameters(GridTestMixin, unittest.TestCase, SetDEPMixin,
|
|||||||
"(of which 5 placed none due to the server being "
|
"(of which 5 placed none due to the server being "
|
||||||
"full and 0 placed none due to an error)",
|
"full and 0 placed none due to an error)",
|
||||||
client.upload,
|
client.upload,
|
||||||
upload.Data("data" * 10000, convergence="")))
|
upload.Data(b"data" * 10000, convergence=b"")))
|
||||||
|
|
||||||
|
|
||||||
# server 1: read-only, no shares
|
# server 1: read-only, no shares
|
||||||
@ -1709,7 +1723,7 @@ class EncodingParameters(GridTestMixin, unittest.TestCase, SetDEPMixin,
|
|||||||
"(of which 4 placed none due to the server being "
|
"(of which 4 placed none due to the server being "
|
||||||
"full and 1 placed none due to an error)",
|
"full and 1 placed none due to an error)",
|
||||||
client.upload,
|
client.upload,
|
||||||
upload.Data("data" * 10000, convergence="")))
|
upload.Data(b"data" * 10000, convergence=b"")))
|
||||||
# server 0, server 1 = empty, accepting shares
|
# server 0, server 1 = empty, accepting shares
|
||||||
# This should place all of the shares, but still fail with happy=4.
|
# This should place all of the shares, but still fail with happy=4.
|
||||||
# We want to make sure that the exception message is worded correctly.
|
# We want to make sure that the exception message is worded correctly.
|
||||||
@ -1725,8 +1739,8 @@ class EncodingParameters(GridTestMixin, unittest.TestCase, SetDEPMixin,
|
|||||||
"server(s). We were asked to place shares on at "
|
"server(s). We were asked to place shares on at "
|
||||||
"least 4 server(s) such that any 3 of them have "
|
"least 4 server(s) such that any 3 of them have "
|
||||||
"enough shares to recover the file.",
|
"enough shares to recover the file.",
|
||||||
client.upload, upload.Data("data" * 10000,
|
client.upload, upload.Data(b"data" * 10000,
|
||||||
convergence="")))
|
convergence=b"")))
|
||||||
# servers 0 - 4 = empty, accepting shares
|
# servers 0 - 4 = empty, accepting shares
|
||||||
# This too should place all the shares, and this too should fail,
|
# This too should place all the shares, and this too should fail,
|
||||||
# but since the effective happiness is more than the k encoding
|
# but since the effective happiness is more than the k encoding
|
||||||
@ -1750,8 +1764,8 @@ class EncodingParameters(GridTestMixin, unittest.TestCase, SetDEPMixin,
|
|||||||
"that any 3 of them have enough shares to recover "
|
"that any 3 of them have enough shares to recover "
|
||||||
"the file, but we were asked to place shares on "
|
"the file, but we were asked to place shares on "
|
||||||
"at least 7 such servers.",
|
"at least 7 such servers.",
|
||||||
client.upload, upload.Data("data" * 10000,
|
client.upload, upload.Data(b"data" * 10000,
|
||||||
convergence="")))
|
convergence=b"")))
|
||||||
# server 0: shares 0 - 9
|
# server 0: shares 0 - 9
|
||||||
# server 1: share 0, read-only
|
# server 1: share 0, read-only
|
||||||
# server 2: share 0, read-only
|
# server 2: share 0, read-only
|
||||||
@ -1782,8 +1796,8 @@ class EncodingParameters(GridTestMixin, unittest.TestCase, SetDEPMixin,
|
|||||||
"to place shares on at least 7 servers such that "
|
"to place shares on at least 7 servers such that "
|
||||||
"any 3 of them have enough shares to recover the "
|
"any 3 of them have enough shares to recover the "
|
||||||
"file",
|
"file",
|
||||||
client.upload, upload.Data("data" * 10000,
|
client.upload, upload.Data(b"data" * 10000,
|
||||||
convergence="")))
|
convergence=b"")))
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
|
||||||
@ -1815,7 +1829,7 @@ class EncodingParameters(GridTestMixin, unittest.TestCase, SetDEPMixin,
|
|||||||
|
|
||||||
d.addCallback(_setup)
|
d.addCallback(_setup)
|
||||||
d.addCallback(lambda client:
|
d.addCallback(lambda client:
|
||||||
client.upload(upload.Data("data" * 10000, convergence="")))
|
client.upload(upload.Data(b"data" * 10000, convergence=b"")))
|
||||||
d.addCallback(lambda ign:
|
d.addCallback(lambda ign:
|
||||||
self.failUnless(self._has_happy_share_distribution()))
|
self.failUnless(self._has_happy_share_distribution()))
|
||||||
return d
|
return d
|
||||||
@ -1873,7 +1887,7 @@ class EncodingParameters(GridTestMixin, unittest.TestCase, SetDEPMixin,
|
|||||||
|
|
||||||
d.addCallback(_setup)
|
d.addCallback(_setup)
|
||||||
d.addCallback(lambda client:
|
d.addCallback(lambda client:
|
||||||
client.upload(upload.Data("data" * 10000, convergence="")))
|
client.upload(upload.Data(b"data" * 10000, convergence=b"")))
|
||||||
d.addCallback(lambda ign:
|
d.addCallback(lambda ign:
|
||||||
self.failUnless(self._has_happy_share_distribution()))
|
self.failUnless(self._has_happy_share_distribution()))
|
||||||
return d
|
return d
|
||||||
@ -1911,7 +1925,7 @@ class EncodingParameters(GridTestMixin, unittest.TestCase, SetDEPMixin,
|
|||||||
return c
|
return c
|
||||||
d.addCallback(_server_setup)
|
d.addCallback(_server_setup)
|
||||||
d.addCallback(lambda client:
|
d.addCallback(lambda client:
|
||||||
client.upload(upload.Data("data" * 10000, convergence="")))
|
client.upload(upload.Data(b"data" * 10000, convergence=b"")))
|
||||||
d.addCallback(lambda ign:
|
d.addCallback(lambda ign:
|
||||||
self.failUnless(self._has_happy_share_distribution()))
|
self.failUnless(self._has_happy_share_distribution()))
|
||||||
return d
|
return d
|
||||||
@ -1935,12 +1949,12 @@ class EncodingParameters(GridTestMixin, unittest.TestCase, SetDEPMixin,
|
|||||||
self._add_server_with_share(server_number=8, share_number=4)
|
self._add_server_with_share(server_number=8, share_number=4)
|
||||||
self._add_server_with_share(server_number=5, share_number=5)
|
self._add_server_with_share(server_number=5, share_number=5)
|
||||||
self._add_server_with_share(server_number=10, share_number=7)
|
self._add_server_with_share(server_number=10, share_number=7)
|
||||||
for i in xrange(4):
|
for i in range(4):
|
||||||
self._copy_share_to_server(i, 2)
|
self._copy_share_to_server(i, 2)
|
||||||
return self.g.clients[0]
|
return self.g.clients[0]
|
||||||
d.addCallback(_server_setup)
|
d.addCallback(_server_setup)
|
||||||
d.addCallback(lambda client:
|
d.addCallback(lambda client:
|
||||||
client.upload(upload.Data("data" * 10000, convergence="")))
|
client.upload(upload.Data(b"data" * 10000, convergence=b"")))
|
||||||
d.addCallback(lambda ign:
|
d.addCallback(lambda ign:
|
||||||
self.failUnless(self._has_happy_share_distribution()))
|
self.failUnless(self._has_happy_share_distribution()))
|
||||||
return d
|
return d
|
||||||
@ -1963,14 +1977,14 @@ class EncodingParameters(GridTestMixin, unittest.TestCase, SetDEPMixin,
|
|||||||
self.shouldFail(UploadUnhappinessError,
|
self.shouldFail(UploadUnhappinessError,
|
||||||
"test_server_selection_bucket_abort",
|
"test_server_selection_bucket_abort",
|
||||||
"",
|
"",
|
||||||
client.upload, upload.Data("data" * 10000,
|
client.upload, upload.Data(b"data" * 10000,
|
||||||
convergence="")))
|
convergence=b"")))
|
||||||
# wait for the abort messages to get there.
|
# wait for the abort messages to get there.
|
||||||
def _turn_barrier(res):
|
def _turn_barrier(res):
|
||||||
return fireEventually(res)
|
return fireEventually(res)
|
||||||
d.addCallback(_turn_barrier)
|
d.addCallback(_turn_barrier)
|
||||||
def _then(ignored):
|
def _then(ignored):
|
||||||
for server in self.g.servers_by_number.values():
|
for server in list(self.g.servers_by_number.values()):
|
||||||
self.failUnlessEqual(server.allocated_size(), 0)
|
self.failUnlessEqual(server.allocated_size(), 0)
|
||||||
d.addCallback(_then)
|
d.addCallback(_then)
|
||||||
return d
|
return d
|
||||||
@ -1996,7 +2010,7 @@ class EncodingParameters(GridTestMixin, unittest.TestCase, SetDEPMixin,
|
|||||||
return fireEventually(res)
|
return fireEventually(res)
|
||||||
d.addCallback(_turn_barrier)
|
d.addCallback(_turn_barrier)
|
||||||
def _then(ignored):
|
def _then(ignored):
|
||||||
for server in self.g.servers_by_number.values():
|
for server in list(self.g.servers_by_number.values()):
|
||||||
self.failUnlessEqual(server.allocated_size(), 0)
|
self.failUnlessEqual(server.allocated_size(), 0)
|
||||||
d.addCallback(_then)
|
d.addCallback(_then)
|
||||||
return d
|
return d
|
||||||
|
@ -1,40 +1,67 @@
|
|||||||
from bs4 import BeautifulSoup
|
import json
|
||||||
from os.path import join
|
from os.path import join
|
||||||
|
|
||||||
|
from bs4 import BeautifulSoup
|
||||||
|
|
||||||
from twisted.trial import unittest
|
from twisted.trial import unittest
|
||||||
from twisted.internet import reactor
|
from twisted.internet import reactor
|
||||||
from foolscap.api import fireEventually, flushEventualQueue
|
|
||||||
from twisted.internet import defer
|
from twisted.internet import defer
|
||||||
from allmydata.introducer import create_introducer
|
|
||||||
|
from foolscap.api import (
|
||||||
|
fireEventually,
|
||||||
|
flushEventualQueue,
|
||||||
|
Tub,
|
||||||
|
)
|
||||||
|
|
||||||
|
import allmydata
|
||||||
|
from allmydata.introducer import (
|
||||||
|
create_introducer,
|
||||||
|
)
|
||||||
|
from allmydata.introducer.server import (
|
||||||
|
_IntroducerNode,
|
||||||
|
)
|
||||||
|
from allmydata.web.introweb import (
|
||||||
|
IntroducerRoot,
|
||||||
|
)
|
||||||
|
|
||||||
from allmydata import node
|
from allmydata import node
|
||||||
from .common import (
|
from .common import (
|
||||||
assert_soup_has_favicon,
|
assert_soup_has_favicon,
|
||||||
assert_soup_has_text,
|
assert_soup_has_text,
|
||||||
|
assert_soup_has_tag_with_attributes,
|
||||||
)
|
)
|
||||||
from ..common import (
|
from ..common import (
|
||||||
SameProcessStreamEndpointAssigner,
|
SameProcessStreamEndpointAssigner,
|
||||||
)
|
)
|
||||||
from ..common_web import do_http
|
from ..common_py3 import (
|
||||||
|
FakeCanary,
|
||||||
|
)
|
||||||
|
from ..common_web import (
|
||||||
|
do_http,
|
||||||
|
render,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class IntroducerWeb(unittest.TestCase):
|
@defer.inlineCallbacks
|
||||||
def setUp(self):
|
def create_introducer_webish(reactor, port_assigner, basedir):
|
||||||
self.node = None
|
"""
|
||||||
self.port_assigner = SameProcessStreamEndpointAssigner()
|
Create and start an introducer node and return it and its ``WebishServer``
|
||||||
self.port_assigner.setUp()
|
service.
|
||||||
self.addCleanup(self.port_assigner.tearDown)
|
|
||||||
|
|
||||||
def tearDown(self):
|
:param reactor: The reactor to use to allow the introducer node to use to
|
||||||
d = defer.succeed(None)
|
listen for connections.
|
||||||
if self.node:
|
|
||||||
d.addCallback(lambda ign: self.node.stopService())
|
|
||||||
d.addCallback(flushEventualQueue)
|
|
||||||
return d
|
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
:param SameProcessStreamEndpointAssigner port_assigner: The assigner to
|
||||||
def test_welcome(self):
|
use to assign a listening port for the introducer node.
|
||||||
basedir = self.mktemp()
|
|
||||||
|
:param bytes basedir: A non-existant path where the introducer node will
|
||||||
|
be created.
|
||||||
|
|
||||||
|
:return Deferred[(_IntroducerNode, WebishServer)]: A Deferred that fires
|
||||||
|
with the node and its webish service.
|
||||||
|
"""
|
||||||
node.create_node_dir(basedir, "testing")
|
node.create_node_dir(basedir, "testing")
|
||||||
_, port_endpoint = self.port_assigner.assign(reactor)
|
_, port_endpoint = port_assigner.assign(reactor)
|
||||||
with open(join(basedir, "tahoe.cfg"), "w") as f:
|
with open(join(basedir, "tahoe.cfg"), "w") as f:
|
||||||
f.write(
|
f.write(
|
||||||
"[node]\n"
|
"[node]\n"
|
||||||
@ -42,16 +69,157 @@ class IntroducerWeb(unittest.TestCase):
|
|||||||
"web.port = {}\n".format(port_endpoint)
|
"web.port = {}\n".format(port_endpoint)
|
||||||
)
|
)
|
||||||
|
|
||||||
self.node = yield create_introducer(basedir)
|
intro_node = yield create_introducer(basedir)
|
||||||
self.ws = self.node.getServiceNamed("webish")
|
ws = intro_node.getServiceNamed("webish")
|
||||||
|
|
||||||
yield fireEventually(None)
|
yield fireEventually(None)
|
||||||
self.node.startService()
|
intro_node.startService()
|
||||||
|
|
||||||
url = "http://localhost:%d/" % self.ws.getPortnum()
|
defer.returnValue((intro_node, ws))
|
||||||
|
|
||||||
|
|
||||||
|
class IntroducerWeb(unittest.TestCase):
|
||||||
|
"""
|
||||||
|
Tests for web-facing functionality of an introducer node.
|
||||||
|
"""
|
||||||
|
def setUp(self):
|
||||||
|
self.node = None
|
||||||
|
self.port_assigner = SameProcessStreamEndpointAssigner()
|
||||||
|
self.port_assigner.setUp()
|
||||||
|
self.addCleanup(self.port_assigner.tearDown)
|
||||||
|
# Anything using Foolscap leaves some timer trash in the reactor that
|
||||||
|
# we have to arrange to have cleaned up.
|
||||||
|
self.addCleanup(lambda: flushEventualQueue(None))
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def test_welcome(self):
|
||||||
|
node, ws = yield create_introducer_webish(
|
||||||
|
reactor,
|
||||||
|
self.port_assigner,
|
||||||
|
self.mktemp(),
|
||||||
|
)
|
||||||
|
self.addCleanup(node.stopService)
|
||||||
|
|
||||||
|
url = "http://localhost:%d/" % (ws.getPortnum(),)
|
||||||
res = yield do_http("get", url)
|
res = yield do_http("get", url)
|
||||||
soup = BeautifulSoup(res, 'html5lib')
|
soup = BeautifulSoup(res, 'html5lib')
|
||||||
assert_soup_has_text(self, soup, u'Welcome to the Tahoe-LAFS Introducer')
|
assert_soup_has_text(self, soup, u'Welcome to the Tahoe-LAFS Introducer')
|
||||||
assert_soup_has_favicon(self, soup)
|
assert_soup_has_favicon(self, soup)
|
||||||
assert_soup_has_text(self, soup, u'Page rendered at')
|
assert_soup_has_text(self, soup, u'Page rendered at')
|
||||||
assert_soup_has_text(self, soup, u'Tahoe-LAFS code imported from:')
|
assert_soup_has_text(self, soup, u'Tahoe-LAFS code imported from:')
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def test_basic_information(self):
|
||||||
|
"""
|
||||||
|
The introducer web page includes the software version and several other
|
||||||
|
simple pieces of information.
|
||||||
|
"""
|
||||||
|
node, ws = yield create_introducer_webish(
|
||||||
|
reactor,
|
||||||
|
self.port_assigner,
|
||||||
|
self.mktemp(),
|
||||||
|
)
|
||||||
|
self.addCleanup(node.stopService)
|
||||||
|
|
||||||
|
url = "http://localhost:%d/" % (ws.getPortnum(),)
|
||||||
|
res = yield do_http("get", url)
|
||||||
|
soup = BeautifulSoup(res, 'html5lib')
|
||||||
|
assert_soup_has_text(
|
||||||
|
self,
|
||||||
|
soup,
|
||||||
|
u"%s: %s" % (allmydata.__appname__, allmydata.__version__),
|
||||||
|
)
|
||||||
|
assert_soup_has_text(self, soup, u"no peers!")
|
||||||
|
assert_soup_has_text(self, soup, u"subscribers!")
|
||||||
|
assert_soup_has_tag_with_attributes(
|
||||||
|
self,
|
||||||
|
soup,
|
||||||
|
"link",
|
||||||
|
{"href": "/tahoe.css"},
|
||||||
|
)
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def test_tahoe_css(self):
|
||||||
|
"""
|
||||||
|
The introducer serves the css.
|
||||||
|
"""
|
||||||
|
node, ws = yield create_introducer_webish(
|
||||||
|
reactor,
|
||||||
|
self.port_assigner,
|
||||||
|
self.mktemp(),
|
||||||
|
)
|
||||||
|
self.addCleanup(node.stopService)
|
||||||
|
|
||||||
|
url = "http://localhost:%d/tahoe.css" % (ws.getPortnum(),)
|
||||||
|
|
||||||
|
# Just don't return an error. If it does, do_http will raise
|
||||||
|
# something.
|
||||||
|
yield do_http("get", url)
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def test_json_front_page(self):
|
||||||
|
"""
|
||||||
|
The front page can be served as json.
|
||||||
|
"""
|
||||||
|
node, ws = yield create_introducer_webish(
|
||||||
|
reactor,
|
||||||
|
self.port_assigner,
|
||||||
|
self.mktemp(),
|
||||||
|
)
|
||||||
|
self.addCleanup(node.stopService)
|
||||||
|
|
||||||
|
url = "http://localhost:%d/?t=json" % (ws.getPortnum(),)
|
||||||
|
res = yield do_http("get", url)
|
||||||
|
data = json.loads(res)
|
||||||
|
self.assertEqual(data["subscription_summary"], {})
|
||||||
|
self.assertEqual(data["announcement_summary"], {})
|
||||||
|
|
||||||
|
|
||||||
|
class IntroducerRootTests(unittest.TestCase):
|
||||||
|
"""
|
||||||
|
Tests for ``IntroducerRoot``.
|
||||||
|
"""
|
||||||
|
def test_json(self):
|
||||||
|
"""
|
||||||
|
The JSON response includes totals for the number of subscriptions and
|
||||||
|
announcements of each service type.
|
||||||
|
"""
|
||||||
|
config = node.config_from_string(self.mktemp(), "", "")
|
||||||
|
config.get_private_path = lambda ignored: self.mktemp()
|
||||||
|
main_tub = Tub()
|
||||||
|
main_tub.listenOn(b"tcp:0")
|
||||||
|
main_tub.setLocation(b"tcp:127.0.0.1:1")
|
||||||
|
introducer_node = _IntroducerNode(config, main_tub, None, None, None)
|
||||||
|
|
||||||
|
introducer_service = introducer_node.getServiceNamed("introducer")
|
||||||
|
for n in range(2):
|
||||||
|
introducer_service.add_subscriber(
|
||||||
|
FakeCanary(),
|
||||||
|
"arbitrary",
|
||||||
|
{"info": "info"},
|
||||||
|
)
|
||||||
|
|
||||||
|
# It would be nice to use the publish method but then we have to
|
||||||
|
# generate a correctly signed message which I don't feel like doing.
|
||||||
|
ann_t = ("msg", "sig", "key")
|
||||||
|
ann = {"service-name": "arbitrary"}
|
||||||
|
introducer_service._announcements[("arbitrary", "key")] = (
|
||||||
|
ann_t,
|
||||||
|
FakeCanary(),
|
||||||
|
ann,
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
|
||||||
|
resource = IntroducerRoot(introducer_node)
|
||||||
|
response = json.loads(
|
||||||
|
self.successResultOf(
|
||||||
|
render(resource, {"t": [b"json"]}),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
response,
|
||||||
|
{
|
||||||
|
u"subscription_summary": {"arbitrary": 2},
|
||||||
|
u"announcement_summary": {"arbitrary": 1},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
@ -4,9 +4,6 @@ from ..common import ShouldFailMixin
|
|||||||
from .. import common_util as testutil
|
from .. import common_util as testutil
|
||||||
|
|
||||||
class Util(ShouldFailMixin, testutil.ReallyEqualMixin, unittest.TestCase):
|
class Util(ShouldFailMixin, testutil.ReallyEqualMixin, unittest.TestCase):
|
||||||
def test_load_file(self):
|
|
||||||
# This will raise an exception unless a well-formed XML file is found under that name.
|
|
||||||
common.getxmlfile('directory.xhtml').load()
|
|
||||||
|
|
||||||
def test_parse_replace_arg(self):
|
def test_parse_replace_arg(self):
|
||||||
self.failUnlessReallyEqual(common.parse_replace_arg("true"), True)
|
self.failUnlessReallyEqual(common.parse_replace_arg("true"), True)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
import os.path, re, urllib, time, cgi
|
import os.path, re, urllib, time
|
||||||
import json
|
import json
|
||||||
import treq
|
import treq
|
||||||
|
|
||||||
@ -8,32 +8,18 @@ from bs4 import BeautifulSoup
|
|||||||
|
|
||||||
from twisted.application import service
|
from twisted.application import service
|
||||||
from twisted.internet import defer
|
from twisted.internet import defer
|
||||||
from twisted.internet.defer import inlineCallbacks, returnValue, maybeDeferred
|
from twisted.internet.defer import inlineCallbacks, returnValue
|
||||||
from twisted.internet.task import Clock
|
from twisted.internet.task import Clock
|
||||||
from twisted.web import client, error, http
|
from twisted.web import client, error, http
|
||||||
from twisted.python import failure, log
|
from twisted.python import failure, log
|
||||||
|
|
||||||
from nevow.context import WebContext
|
|
||||||
from nevow.inevow import (
|
|
||||||
ICanHandleException,
|
|
||||||
IRequest,
|
|
||||||
IData,
|
|
||||||
)
|
|
||||||
from nevow.util import escapeToXML
|
|
||||||
from nevow.loaders import stan
|
|
||||||
from nevow.testutil import FakeRequest
|
|
||||||
from nevow.appserver import (
|
|
||||||
processingFailed,
|
|
||||||
DefaultExceptionHandler,
|
|
||||||
)
|
|
||||||
|
|
||||||
from allmydata import interfaces, uri, webish
|
from allmydata import interfaces, uri, webish
|
||||||
from allmydata.storage_client import StorageFarmBroker, StubServer
|
from allmydata.storage_client import StorageFarmBroker, StubServer
|
||||||
from allmydata.immutable import upload
|
from allmydata.immutable import upload
|
||||||
from allmydata.immutable.downloader.status import DownloadStatus
|
from allmydata.immutable.downloader.status import DownloadStatus
|
||||||
from allmydata.dirnode import DirectoryNode
|
from allmydata.dirnode import DirectoryNode
|
||||||
from allmydata.nodemaker import NodeMaker
|
from allmydata.nodemaker import NodeMaker
|
||||||
from allmydata.web.common import WebError, MultiFormatPage
|
from allmydata.web.common import MultiFormatResource
|
||||||
from allmydata.util import fileutil, base32, hashutil
|
from allmydata.util import fileutil, base32, hashutil
|
||||||
from allmydata.util.consumer import download_to_data
|
from allmydata.util.consumer import download_to_data
|
||||||
from allmydata.util.encodingutil import to_bytes
|
from allmydata.util.encodingutil import to_bytes
|
||||||
@ -70,6 +56,7 @@ from ..common_py3 import TimezoneMixin
|
|||||||
from ..common_web import (
|
from ..common_web import (
|
||||||
do_http,
|
do_http,
|
||||||
Error,
|
Error,
|
||||||
|
render,
|
||||||
)
|
)
|
||||||
from ...web.common import (
|
from ...web.common import (
|
||||||
humanize_exception,
|
humanize_exception,
|
||||||
@ -385,9 +372,6 @@ class WebMixin(TimezoneMixin):
|
|||||||
self._htmlname_unicode = u"<&weirdly'named\"file>>>_<iframe />.txt"
|
self._htmlname_unicode = u"<&weirdly'named\"file>>>_<iframe />.txt"
|
||||||
self._htmlname_raw = self._htmlname_unicode.encode('utf-8')
|
self._htmlname_raw = self._htmlname_unicode.encode('utf-8')
|
||||||
self._htmlname_urlencoded = urllib.quote(self._htmlname_raw, '')
|
self._htmlname_urlencoded = urllib.quote(self._htmlname_raw, '')
|
||||||
self._htmlname_escaped = escapeToXML(self._htmlname_raw)
|
|
||||||
self._htmlname_escaped_attr = cgi.escape(self._htmlname_raw, quote=True)
|
|
||||||
self._htmlname_escaped_double = escapeToXML(cgi.escape(self._htmlname_raw, quote=True))
|
|
||||||
self.HTMLNAME_CONTENTS, n, self._htmlname_txt_uri = self.makefile(0)
|
self.HTMLNAME_CONTENTS, n, self._htmlname_txt_uri = self.makefile(0)
|
||||||
foo.set_uri(self._htmlname_unicode, self._htmlname_txt_uri, self._htmlname_txt_uri)
|
foo.set_uri(self._htmlname_unicode, self._htmlname_txt_uri, self._htmlname_txt_uri)
|
||||||
|
|
||||||
@ -665,55 +649,35 @@ class WebMixin(TimezoneMixin):
|
|||||||
(which, res))
|
(which, res))
|
||||||
|
|
||||||
|
|
||||||
|
class MultiFormatResourceTests(TrialTestCase):
|
||||||
|
"""
|
||||||
|
Tests for ``MultiFormatResource``.
|
||||||
|
"""
|
||||||
|
def render(self, resource, **queryargs):
|
||||||
|
return self.successResultOf(render(resource, queryargs))
|
||||||
|
|
||||||
class MultiFormatPageTests(TrialTestCase):
|
|
||||||
"""
|
|
||||||
Tests for ``MultiFormatPage``.
|
|
||||||
"""
|
|
||||||
def resource(self):
|
def resource(self):
|
||||||
"""
|
"""
|
||||||
Create and return an instance of a ``MultiFormatPage`` subclass with two
|
Create and return an instance of a ``MultiFormatResource`` subclass
|
||||||
formats: ``a`` and ``b``.
|
with a default HTML format, and two custom formats: ``a`` and ``b``.
|
||||||
"""
|
"""
|
||||||
class Content(MultiFormatPage):
|
class Content(MultiFormatResource):
|
||||||
docFactory = stan("doc factory")
|
|
||||||
|
def render_HTML(self, req):
|
||||||
|
return "html"
|
||||||
|
|
||||||
def render_A(self, req):
|
def render_A(self, req):
|
||||||
return "a"
|
return "a"
|
||||||
|
|
||||||
def render_B(self, req):
|
def render_B(self, req):
|
||||||
return "b"
|
return "b"
|
||||||
|
|
||||||
return Content()
|
return Content()
|
||||||
|
|
||||||
|
|
||||||
def render(self, resource, **query_args):
|
|
||||||
"""
|
|
||||||
Render a Nevow ``Page`` against a request with the given query arguments.
|
|
||||||
|
|
||||||
:param resource: The Nevow resource to render.
|
|
||||||
|
|
||||||
:param query_args: The query arguments to put into the request being
|
|
||||||
rendered. A mapping from ``bytes`` to ``list`` of ``bytes``.
|
|
||||||
|
|
||||||
:return: The rendered response body as ``bytes``.
|
|
||||||
"""
|
|
||||||
ctx = WebContext(tag=resource)
|
|
||||||
req = FakeRequest(args=query_args)
|
|
||||||
ctx.remember(DefaultExceptionHandler(), ICanHandleException)
|
|
||||||
ctx.remember(req, IRequest)
|
|
||||||
ctx.remember(None, IData)
|
|
||||||
|
|
||||||
d = maybeDeferred(resource.renderHTTP, ctx)
|
|
||||||
d.addErrback(processingFailed, req, ctx)
|
|
||||||
res = self.successResultOf(d)
|
|
||||||
if isinstance(res, bytes):
|
|
||||||
return req.v + res
|
|
||||||
return req.v
|
|
||||||
|
|
||||||
|
|
||||||
def test_select_format(self):
|
def test_select_format(self):
|
||||||
"""
|
"""
|
||||||
The ``formatArgument`` attribute of a ``MultiFormatPage`` subclass
|
The ``formatArgument`` attribute of a ``MultiFormatResource`` subclass
|
||||||
identifies the query argument which selects the result format.
|
identifies the query argument which selects the result format.
|
||||||
"""
|
"""
|
||||||
resource = self.resource()
|
resource = self.resource()
|
||||||
@ -723,8 +687,8 @@ class MultiFormatPageTests(TrialTestCase):
|
|||||||
|
|
||||||
def test_default_format_argument(self):
|
def test_default_format_argument(self):
|
||||||
"""
|
"""
|
||||||
If a ``MultiFormatPage`` subclass does not set ``formatArgument`` then the
|
If a ``MultiFormatResource`` subclass does not set ``formatArgument``
|
||||||
``t`` argument is used.
|
then the ``t`` argument is used.
|
||||||
"""
|
"""
|
||||||
resource = self.resource()
|
resource = self.resource()
|
||||||
self.assertEqual("a", self.render(resource, t=["a"]))
|
self.assertEqual("a", self.render(resource, t=["a"]))
|
||||||
@ -733,16 +697,15 @@ class MultiFormatPageTests(TrialTestCase):
|
|||||||
def test_no_format(self):
|
def test_no_format(self):
|
||||||
"""
|
"""
|
||||||
If no value is given for the format argument and no default format has
|
If no value is given for the format argument and no default format has
|
||||||
been defined, the base Nevow rendering behavior is used
|
been defined, the base rendering behavior is used (``render_HTML``).
|
||||||
(``renderHTTP``).
|
|
||||||
"""
|
"""
|
||||||
resource = self.resource()
|
resource = self.resource()
|
||||||
self.assertEqual("doc factory", self.render(resource))
|
self.assertEqual("html", self.render(resource))
|
||||||
|
|
||||||
|
|
||||||
def test_default_format(self):
|
def test_default_format(self):
|
||||||
"""
|
"""
|
||||||
If no value is given for the format argument and the ``MultiFormatPage``
|
If no value is given for the format argument and the ``MultiFormatResource``
|
||||||
subclass defines a ``formatDefault``, that value is used as the format
|
subclass defines a ``formatDefault``, that value is used as the format
|
||||||
to render.
|
to render.
|
||||||
"""
|
"""
|
||||||
@ -754,11 +717,11 @@ class MultiFormatPageTests(TrialTestCase):
|
|||||||
def test_explicit_none_format_renderer(self):
|
def test_explicit_none_format_renderer(self):
|
||||||
"""
|
"""
|
||||||
If a format is selected which has a renderer set to ``None``, the base
|
If a format is selected which has a renderer set to ``None``, the base
|
||||||
Nevow rendering behavior is used (``renderHTTP``).
|
rendering behavior is used (``render_HTML``).
|
||||||
"""
|
"""
|
||||||
resource = self.resource()
|
resource = self.resource()
|
||||||
resource.render_FOO = None
|
resource.render_FOO = None
|
||||||
self.assertEqual("doc factory", self.render(resource, t=["foo"]))
|
self.assertEqual("html", self.render(resource, t=["foo"]))
|
||||||
|
|
||||||
|
|
||||||
def test_unknown_format(self):
|
def test_unknown_format(self):
|
||||||
@ -767,12 +730,13 @@ class MultiFormatPageTests(TrialTestCase):
|
|||||||
returned.
|
returned.
|
||||||
"""
|
"""
|
||||||
resource = self.resource()
|
resource = self.resource()
|
||||||
|
response_body = self.render(resource, t=["foo"])
|
||||||
self.assertIn(
|
self.assertIn(
|
||||||
"<title>Exception</title>",
|
"<title>400 - Bad Format</title>", response_body,
|
||||||
self.render(resource, t=["foo"]),
|
)
|
||||||
|
self.assertIn(
|
||||||
|
"Unknown t value: 'foo'", response_body,
|
||||||
)
|
)
|
||||||
self.flushLoggedErrors(WebError)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixin, TrialTestCase):
|
class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixin, TrialTestCase):
|
||||||
@ -781,20 +745,41 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
|
|||||||
def test_create(self):
|
def test_create(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def test_frame_options(self):
|
def _assertResponseHeaders(self, name, values):
|
||||||
"""
|
"""
|
||||||
All pages deny the ability to be loaded in frames.
|
Assert that the resource at **/** is served with a response header named
|
||||||
|
``name`` and values ``values``.
|
||||||
|
|
||||||
|
:param bytes name: The name of the header item to check.
|
||||||
|
:param [bytes] values: The expected values.
|
||||||
|
|
||||||
|
:return Deferred: A Deferred that fires successfully if the expected
|
||||||
|
header item is found and which fails otherwise.
|
||||||
"""
|
"""
|
||||||
d = self.GET("/", return_response=True)
|
d = self.GET("/", return_response=True)
|
||||||
def responded(result):
|
def responded(result):
|
||||||
_, _, headers = result
|
_, _, headers = result
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
[b"DENY"],
|
values,
|
||||||
headers.getRawHeaders(b"X-Frame-Options"),
|
headers.getRawHeaders(name),
|
||||||
)
|
)
|
||||||
d.addCallback(responded)
|
d.addCallback(responded)
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
def test_frame_options(self):
|
||||||
|
"""
|
||||||
|
Pages deny the ability to be loaded in frames.
|
||||||
|
"""
|
||||||
|
# It should be all pages but we only demonstrate it for / with this test.
|
||||||
|
return self._assertResponseHeaders(b"X-Frame-Options", [b"DENY"])
|
||||||
|
|
||||||
|
def test_referrer_policy(self):
|
||||||
|
"""
|
||||||
|
Pages set a **no-referrer** policy.
|
||||||
|
"""
|
||||||
|
# It should be all pages but we only demonstrate it for / with this test.
|
||||||
|
return self._assertResponseHeaders(b"Referrer-Policy", [b"no-referrer"])
|
||||||
|
|
||||||
def test_welcome_json(self):
|
def test_welcome_json(self):
|
||||||
"""
|
"""
|
||||||
There is a JSON version of the welcome page which can be selected with the
|
There is a JSON version of the welcome page which can be selected with the
|
||||||
@ -1989,15 +1974,6 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
# XXX leaving this as-is, but consider using beautfulsoup here too?
|
|
||||||
# Make sure that Nevow escaping actually works by checking for unsafe characters
|
|
||||||
# and that '&' is escaped.
|
|
||||||
for entity in '<>':
|
|
||||||
self.failUnlessIn(entity, self._htmlname_raw)
|
|
||||||
self.failIfIn(entity, self._htmlname_escaped)
|
|
||||||
self.failUnlessIn('&', re.sub(r'&(amp|lt|gt|quot|apos);', '', self._htmlname_raw))
|
|
||||||
self.failIfIn('&', re.sub(r'&(amp|lt|gt|quot|apos);', '', self._htmlname_escaped))
|
|
||||||
|
|
||||||
@inlineCallbacks
|
@inlineCallbacks
|
||||||
def test_GET_root_html(self):
|
def test_GET_root_html(self):
|
||||||
data = yield self.GET("/")
|
data = yield self.GET("/")
|
||||||
|
@ -34,6 +34,7 @@ PORTED_MODULES = [
|
|||||||
"allmydata.hashtree",
|
"allmydata.hashtree",
|
||||||
"allmydata.immutable.happiness_upload",
|
"allmydata.immutable.happiness_upload",
|
||||||
"allmydata.interfaces",
|
"allmydata.interfaces",
|
||||||
|
"allmydata.introducer.interfaces",
|
||||||
"allmydata.monitor",
|
"allmydata.monitor",
|
||||||
"allmydata.storage.common",
|
"allmydata.storage.common",
|
||||||
"allmydata.storage.crawler",
|
"allmydata.storage.crawler",
|
||||||
@ -79,18 +80,23 @@ PORTED_TEST_MODULES = [
|
|||||||
"allmydata.test.test_base32",
|
"allmydata.test.test_base32",
|
||||||
"allmydata.test.test_base62",
|
"allmydata.test.test_base62",
|
||||||
"allmydata.test.test_codec",
|
"allmydata.test.test_codec",
|
||||||
|
"allmydata.test.test_common_util",
|
||||||
"allmydata.test.test_configutil",
|
"allmydata.test.test_configutil",
|
||||||
"allmydata.test.test_connection_status",
|
"allmydata.test.test_connection_status",
|
||||||
"allmydata.test.test_crawler",
|
"allmydata.test.test_crawler",
|
||||||
"allmydata.test.test_crypto",
|
"allmydata.test.test_crypto",
|
||||||
"allmydata.test.test_deferredutil",
|
"allmydata.test.test_deferredutil",
|
||||||
"allmydata.test.test_dictutil",
|
"allmydata.test.test_dictutil",
|
||||||
|
"allmydata.test.test_download",
|
||||||
"allmydata.test.test_encode",
|
"allmydata.test.test_encode",
|
||||||
"allmydata.test.test_encodingutil",
|
"allmydata.test.test_encodingutil",
|
||||||
|
"allmydata.test.test_filenode",
|
||||||
"allmydata.test.test_happiness",
|
"allmydata.test.test_happiness",
|
||||||
"allmydata.test.test_hashtree",
|
"allmydata.test.test_hashtree",
|
||||||
"allmydata.test.test_hashutil",
|
"allmydata.test.test_hashutil",
|
||||||
|
"allmydata.test.test_helper",
|
||||||
"allmydata.test.test_humanreadable",
|
"allmydata.test.test_humanreadable",
|
||||||
|
"allmydata.test.test_immutable",
|
||||||
"allmydata.test.test_iputil",
|
"allmydata.test.test_iputil",
|
||||||
"allmydata.test.test_log",
|
"allmydata.test.test_log",
|
||||||
"allmydata.test.test_monitor",
|
"allmydata.test.test_monitor",
|
||||||
@ -104,6 +110,7 @@ PORTED_TEST_MODULES = [
|
|||||||
"allmydata.test.test_storage",
|
"allmydata.test.test_storage",
|
||||||
"allmydata.test.test_storage_web",
|
"allmydata.test.test_storage_web",
|
||||||
"allmydata.test.test_time_format",
|
"allmydata.test.test_time_format",
|
||||||
|
"allmydata.test.test_upload",
|
||||||
"allmydata.test.test_uri",
|
"allmydata.test.test_uri",
|
||||||
"allmydata.test.test_util",
|
"allmydata.test.test_util",
|
||||||
"allmydata.test.test_version",
|
"allmydata.test.test_version",
|
||||||
|
@ -180,17 +180,6 @@ class HookMixin(object):
|
|||||||
log.msg(msg, level=log.NOISY)
|
log.msg(msg, level=log.NOISY)
|
||||||
|
|
||||||
|
|
||||||
def for_items(cb, mapping):
|
|
||||||
"""
|
|
||||||
For each (key, value) pair in a mapping, I add a callback to cb(None, key, value)
|
|
||||||
to a Deferred that fires immediately. I return that Deferred.
|
|
||||||
"""
|
|
||||||
d = defer.succeed(None)
|
|
||||||
for k, v in mapping.items():
|
|
||||||
d.addCallback(lambda ign, k=k, v=v: cb(None, k, v))
|
|
||||||
return d
|
|
||||||
|
|
||||||
|
|
||||||
class WaitForDelayedCallsMixin(PollMixin):
|
class WaitForDelayedCallsMixin(PollMixin):
|
||||||
def _delayed_calls_done(self):
|
def _delayed_calls_done(self):
|
||||||
# We're done when the only remaining DelayedCalls fire after threshold.
|
# We're done when the only remaining DelayedCalls fire after threshold.
|
||||||
|
@ -24,7 +24,7 @@ class DictOfSets(dict):
|
|||||||
self[key] = set([value])
|
self[key] = set([value])
|
||||||
|
|
||||||
def update(self, otherdictofsets):
|
def update(self, otherdictofsets):
|
||||||
for key, values in otherdictofsets.items():
|
for key, values in list(otherdictofsets.items()):
|
||||||
if key in self:
|
if key in self:
|
||||||
self[key].update(values)
|
self[key].update(values)
|
||||||
else:
|
else:
|
||||||
|
@ -3,21 +3,39 @@ import time
|
|||||||
import json
|
import json
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
|
|
||||||
from twisted.web import http, server, resource, template
|
from twisted.web import (
|
||||||
|
http,
|
||||||
|
resource,
|
||||||
|
server,
|
||||||
|
template,
|
||||||
|
)
|
||||||
from twisted.python import log
|
from twisted.python import log
|
||||||
from nevow import loaders, appserver
|
from nevow import appserver
|
||||||
from nevow.rend import Page
|
|
||||||
from nevow.inevow import IRequest
|
from nevow.inevow import IRequest
|
||||||
from nevow.util import resource_filename
|
|
||||||
from allmydata import blacklist
|
from allmydata import blacklist
|
||||||
from allmydata.interfaces import ExistingChildError, NoSuchChildError, \
|
from allmydata.interfaces import (
|
||||||
FileTooLargeError, NotEnoughSharesError, NoSharesError, \
|
EmptyPathnameComponentError,
|
||||||
EmptyPathnameComponentError, MustBeDeepImmutableError, \
|
ExistingChildError,
|
||||||
MustBeReadonlyError, MustNotBeUnknownRWError, SDMF_VERSION, MDMF_VERSION
|
FileTooLargeError,
|
||||||
|
MustBeDeepImmutableError,
|
||||||
|
MustBeReadonlyError,
|
||||||
|
MustNotBeUnknownRWError,
|
||||||
|
NoSharesError,
|
||||||
|
NoSuchChildError,
|
||||||
|
NotEnoughSharesError,
|
||||||
|
MDMF_VERSION,
|
||||||
|
SDMF_VERSION,
|
||||||
|
)
|
||||||
from allmydata.mutable.common import UnrecoverableFileError
|
from allmydata.mutable.common import UnrecoverableFileError
|
||||||
from allmydata.util.hashutil import timing_safe_compare
|
from allmydata.util.hashutil import timing_safe_compare
|
||||||
from allmydata.util.time_format import format_time, format_delta
|
from allmydata.util.time_format import (
|
||||||
from allmydata.util.encodingutil import to_bytes, quote_output
|
format_delta,
|
||||||
|
format_time,
|
||||||
|
)
|
||||||
|
from allmydata.util.encodingutil import (
|
||||||
|
quote_output,
|
||||||
|
to_bytes,
|
||||||
|
)
|
||||||
|
|
||||||
# Originally part of this module, so still part of its API:
|
# Originally part of this module, so still part of its API:
|
||||||
from .common_py3 import ( # noqa: F401
|
from .common_py3 import ( # noqa: F401
|
||||||
@ -42,9 +60,6 @@ def get_filenode_metadata(filenode):
|
|||||||
metadata['size'] = size
|
metadata['size'] = size
|
||||||
return metadata
|
return metadata
|
||||||
|
|
||||||
def getxmlfile(name):
|
|
||||||
return loaders.xmlfile(resource_filename('allmydata.web', '%s' % name))
|
|
||||||
|
|
||||||
def boolean_of_arg(arg):
|
def boolean_of_arg(arg):
|
||||||
# TODO: ""
|
# TODO: ""
|
||||||
if arg.lower() not in ("true", "t", "1", "false", "f", "0", "on", "off"):
|
if arg.lower() not in ("true", "t", "1", "false", "f", "0", "on", "off"):
|
||||||
@ -353,62 +368,6 @@ class NeedOperationHandleError(WebError):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class MultiFormatPage(Page):
|
|
||||||
"""
|
|
||||||
```MultiFormatPage`` is a ``rend.Page`` that can be rendered in a number
|
|
||||||
of different formats.
|
|
||||||
|
|
||||||
Rendered format is controlled by a query argument (given by
|
|
||||||
``self.formatArgument``). Different resources may support different
|
|
||||||
formats but ``json`` is a pretty common one.
|
|
||||||
"""
|
|
||||||
formatArgument = "t"
|
|
||||||
formatDefault = None
|
|
||||||
|
|
||||||
def renderHTTP(self, ctx):
|
|
||||||
"""
|
|
||||||
Dispatch to a renderer for a particular format, as selected by a query
|
|
||||||
argument.
|
|
||||||
|
|
||||||
A renderer for the format given by the query argument matching
|
|
||||||
``formatArgument`` will be selected and invoked. The default ``Page``
|
|
||||||
rendering behavior will be used if no format is selected (either by
|
|
||||||
query arguments or by ``formatDefault``).
|
|
||||||
|
|
||||||
:return: The result of the selected renderer.
|
|
||||||
"""
|
|
||||||
req = IRequest(ctx)
|
|
||||||
t = get_arg(req, self.formatArgument, self.formatDefault)
|
|
||||||
renderer = self._get_renderer(t)
|
|
||||||
result = renderer(ctx)
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def _get_renderer(self, fmt):
|
|
||||||
"""
|
|
||||||
Get the renderer for the indicated format.
|
|
||||||
|
|
||||||
:param bytes fmt: The format. If a method with a prefix of
|
|
||||||
``render_`` and a suffix of this format (upper-cased) is found, it
|
|
||||||
will be used.
|
|
||||||
|
|
||||||
:return: A callable which takes a Nevow context and renders a
|
|
||||||
response.
|
|
||||||
"""
|
|
||||||
if fmt is None:
|
|
||||||
return super(MultiFormatPage, self).renderHTTP
|
|
||||||
try:
|
|
||||||
renderer = getattr(self, "render_{}".format(fmt.upper()))
|
|
||||||
except AttributeError:
|
|
||||||
raise WebError(
|
|
||||||
"Unknown {} value: {!r}".format(self.formatArgument, fmt),
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
if renderer is None:
|
|
||||||
return super(MultiFormatPage, self).renderHTTP
|
|
||||||
return lambda ctx: renderer(IRequest(ctx))
|
|
||||||
|
|
||||||
|
|
||||||
class SlotsSequenceElement(template.Element):
|
class SlotsSequenceElement(template.Element):
|
||||||
"""
|
"""
|
||||||
``SlotsSequenceElement` is a minimal port of nevow's sequence renderer for
|
``SlotsSequenceElement` is a minimal port of nevow's sequence renderer for
|
||||||
|
@ -94,9 +94,11 @@ class MultiFormatResource(resource.Resource, object):
|
|||||||
try:
|
try:
|
||||||
renderer = getattr(self, "render_{}".format(fmt.upper()))
|
renderer = getattr(self, "render_{}".format(fmt.upper()))
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
raise WebError(
|
return resource.ErrorPage(
|
||||||
|
http.BAD_REQUEST,
|
||||||
|
"Bad Format",
|
||||||
"Unknown {} value: {!r}".format(self.formatArgument, fmt),
|
"Unknown {} value: {!r}".format(self.formatArgument, fmt),
|
||||||
)
|
).render
|
||||||
|
|
||||||
if renderer is None:
|
if renderer is None:
|
||||||
renderer = self.render_HTML
|
renderer = self.render_HTML
|
||||||
|
@ -20,6 +20,7 @@ from allmydata.web.common import (
|
|||||||
WebError,
|
WebError,
|
||||||
get_format,
|
get_format,
|
||||||
get_mutable_type,
|
get_mutable_type,
|
||||||
|
render_exception,
|
||||||
)
|
)
|
||||||
from allmydata.web import status
|
from allmydata.web import status
|
||||||
|
|
||||||
@ -83,6 +84,7 @@ class UploadResultsPage(Resource, object):
|
|||||||
super(UploadResultsPage, self).__init__()
|
super(UploadResultsPage, self).__init__()
|
||||||
self._upload_results = upload_results
|
self._upload_results = upload_results
|
||||||
|
|
||||||
|
@render_exception
|
||||||
def render_POST(self, req):
|
def render_POST(self, req):
|
||||||
elem = UploadResultsElement(self._upload_results)
|
elem = UploadResultsElement(self._upload_results)
|
||||||
return renderElement(req, elem)
|
return renderElement(req, elem)
|
||||||
|
Loading…
Reference in New Issue
Block a user