summaryrefslogtreecommitdiffstats
path: root/vdslib
diff options
context:
space:
mode:
authorJon Bratseth <bratseth@yahoo-inc.com>2016-06-15 23:09:44 +0200
committerJon Bratseth <bratseth@yahoo-inc.com>2016-06-15 23:09:44 +0200
commit72231250ed81e10d66bfe70701e64fa5fe50f712 (patch)
tree2728bba1131a6f6e5bdf95afec7d7ff9358dac50 /vdslib
Publish
Diffstat (limited to 'vdslib')
-rw-r--r--vdslib/.gitignore5
-rw-r--r--vdslib/CMakeLists.txt30
-rw-r--r--vdslib/OWNERS2
-rw-r--r--vdslib/README1
-rw-r--r--vdslib/pom.xml109
-rw-r--r--vdslib/src/.gitignore4
-rw-r--r--vdslib/src/main/java/com/yahoo/vdslib/BinaryDocumentList.java55
-rw-r--r--vdslib/src/main/java/com/yahoo/vdslib/BinaryEntry.java82
-rw-r--r--vdslib/src/main/java/com/yahoo/vdslib/BucketDistribution.java205
-rw-r--r--vdslib/src/main/java/com/yahoo/vdslib/DocumentList.java108
-rw-r--r--vdslib/src/main/java/com/yahoo/vdslib/DocumentSummary.java70
-rw-r--r--vdslib/src/main/java/com/yahoo/vdslib/DynamicDocumentList.java161
-rw-r--r--vdslib/src/main/java/com/yahoo/vdslib/DynamicEntry.java75
-rw-r--r--vdslib/src/main/java/com/yahoo/vdslib/Entry.java159
-rw-r--r--vdslib/src/main/java/com/yahoo/vdslib/MetaEntry.java52
-rw-r--r--vdslib/src/main/java/com/yahoo/vdslib/SearchResult.java119
-rw-r--r--vdslib/src/main/java/com/yahoo/vdslib/VisitorOrdering.java40
-rw-r--r--vdslib/src/main/java/com/yahoo/vdslib/VisitorStatistics.java57
-rw-r--r--vdslib/src/main/java/com/yahoo/vdslib/distribution/ConfiguredNode.java42
-rw-r--r--vdslib/src/main/java/com/yahoo/vdslib/distribution/Distribution.java536
-rw-r--r--vdslib/src/main/java/com/yahoo/vdslib/distribution/Group.java300
-rw-r--r--vdslib/src/main/java/com/yahoo/vdslib/distribution/GroupVisitor.java8
-rw-r--r--vdslib/src/main/java/com/yahoo/vdslib/distribution/RandomGen.java18
-rw-r--r--vdslib/src/main/java/com/yahoo/vdslib/distribution/package-info.java5
-rw-r--r--vdslib/src/main/java/com/yahoo/vdslib/loadtype/.gitignore0
-rw-r--r--vdslib/src/main/java/com/yahoo/vdslib/package-info.java5
-rw-r--r--vdslib/src/main/java/com/yahoo/vdslib/state/ClusterState.java403
-rw-r--r--vdslib/src/main/java/com/yahoo/vdslib/state/Diff.java121
-rw-r--r--vdslib/src/main/java/com/yahoo/vdslib/state/DiskState.java128
-rw-r--r--vdslib/src/main/java/com/yahoo/vdslib/state/Node.java52
-rw-r--r--vdslib/src/main/java/com/yahoo/vdslib/state/NodeState.java499
-rw-r--r--vdslib/src/main/java/com/yahoo/vdslib/state/NodeType.java32
-rw-r--r--vdslib/src/main/java/com/yahoo/vdslib/state/State.java82
-rw-r--r--vdslib/src/main/java/com/yahoo/vdslib/state/package-info.java5
-rw-r--r--vdslib/src/test/files/documentlist-java.datbin0 -> 358 bytes
-rw-r--r--vdslib/src/test/files/documentmanager.cfg91
-rw-r--r--vdslib/src/test/files/documenttypes.cfg126
-rw-r--r--vdslib/src/test/java/com/yahoo/vdslib/BucketDistributionTestCase.java111
-rw-r--r--vdslib/src/test/java/com/yahoo/vdslib/DocumentListTestCase.java135
-rw-r--r--vdslib/src/test/java/com/yahoo/vdslib/EntryTestCase.java51
-rw-r--r--vdslib/src/test/java/com/yahoo/vdslib/SearchResultTestCase.java92
-rw-r--r--vdslib/src/test/java/com/yahoo/vdslib/VisitorOrderingTestCase.java40
-rw-r--r--vdslib/src/test/java/com/yahoo/vdslib/distribution/CrossPlatformTestFactory.java52
-rw-r--r--vdslib/src/test/java/com/yahoo/vdslib/distribution/DistributionTestCase.java387
-rw-r--r--vdslib/src/test/java/com/yahoo/vdslib/distribution/DistributionTestFactory.java250
-rw-r--r--vdslib/src/test/java/com/yahoo/vdslib/distribution/GroupTestCase.java188
-rw-r--r--vdslib/src/test/java/com/yahoo/vdslib/state/ClusterStateTestCase.java246
-rw-r--r--vdslib/src/test/java/com/yahoo/vdslib/state/DiskStateTestCase.java106
-rw-r--r--vdslib/src/test/java/com/yahoo/vdslib/state/NodeStateTestCase.java231
-rw-r--r--vdslib/src/test/java/com/yahoo/vdslib/state/NodeTest.java87
-rw-r--r--vdslib/src/tests/.gitignore6
-rw-r--r--vdslib/src/tests/CMakeLists.txt12
-rw-r--r--vdslib/src/tests/bucketdistribution/.gitignore3
-rw-r--r--vdslib/src/tests/bucketdistribution/CMakeLists.txt6
-rw-r--r--vdslib/src/tests/bucketdistribution/bucketdistributiontest.cpp116
-rw-r--r--vdslib/src/tests/container/.gitignore3
-rw-r--r--vdslib/src/tests/container/CMakeLists.txt12
-rw-r--r--vdslib/src/tests/container/documentlisttest.cpp538
-rw-r--r--vdslib/src/tests/container/documentsummarytest.cpp53
-rw-r--r--vdslib/src/tests/container/indexedcontaineriteratortest.cpp61
-rw-r--r--vdslib/src/tests/container/lruordertest.cpp109
-rw-r--r--vdslib/src/tests/container/parameterstest.cpp53
-rw-r--r--vdslib/src/tests/container/searchresulttest.cpp85
-rw-r--r--vdslib/src/tests/container/smallvectortest.cpp274
-rw-r--r--vdslib/src/tests/cpp-distribution.txt100
-rw-r--r--vdslib/src/tests/cpp-distribution2.txt100
-rw-r--r--vdslib/src/tests/cpp-hierarchical-distribution.txt100
-rw-r--r--vdslib/src/tests/distribution/.gitignore3
-rw-r--r--vdslib/src/tests/distribution/CMakeLists.txt9
-rw-r--r--vdslib/src/tests/distribution/bucketvector.cpp106
-rw-r--r--vdslib/src/tests/distribution/bucketvector.h16
-rw-r--r--vdslib/src/tests/distribution/datadistributiontest.cpp665
-rw-r--r--vdslib/src/tests/distribution/distributiontest.cpp1507
-rw-r--r--vdslib/src/tests/distribution/grouptest.cpp90
-rw-r--r--vdslib/src/tests/distribution/idealnodecalculatorcachetest.cpp331
-rw-r--r--vdslib/src/tests/distribution/idealnodecalculatorimpltest.cpp46
-rw-r--r--vdslib/src/tests/distribution/randombucket.cpp51
-rw-r--r--vdslib/src/tests/distribution/randombucket.h11
-rw-r--r--vdslib/src/tests/distribution/testdata/.gitignore1
-rw-r--r--vdslib/src/tests/distribution/testdata/41-distributordistribution65536
-rw-r--r--vdslib/src/tests/distribution/testdata/abovesplitbit.java.results225
-rw-r--r--vdslib/src/tests/distribution/testdata/distbit0.java.results510
-rw-r--r--vdslib/src/tests/distribution/testdata/distbit1.java.results510
-rw-r--r--vdslib/src/tests/distribution/testdata/distbit10.java.results510
-rw-r--r--vdslib/src/tests/distribution/testdata/distbit11.java.results510
-rw-r--r--vdslib/src/tests/distribution/testdata/distbit12.java.results510
-rw-r--r--vdslib/src/tests/distribution/testdata/distbit13.java.results510
-rw-r--r--vdslib/src/tests/distribution/testdata/distbit14.java.results510
-rw-r--r--vdslib/src/tests/distribution/testdata/distbit15.java.results510
-rw-r--r--vdslib/src/tests/distribution/testdata/distbit16.java.results510
-rw-r--r--vdslib/src/tests/distribution/testdata/distbit17.java.results510
-rw-r--r--vdslib/src/tests/distribution/testdata/distbit18.java.results510
-rw-r--r--vdslib/src/tests/distribution/testdata/distbit19.java.results510
-rw-r--r--vdslib/src/tests/distribution/testdata/distbit2.java.results510
-rw-r--r--vdslib/src/tests/distribution/testdata/distbit20.java.results510
-rw-r--r--vdslib/src/tests/distribution/testdata/distbit21.java.results510
-rw-r--r--vdslib/src/tests/distribution/testdata/distbit22.java.results510
-rw-r--r--vdslib/src/tests/distribution/testdata/distbit23.java.results510
-rw-r--r--vdslib/src/tests/distribution/testdata/distbit24.java.results510
-rw-r--r--vdslib/src/tests/distribution/testdata/distbit25.java.results510
-rw-r--r--vdslib/src/tests/distribution/testdata/distbit26.java.results510
-rw-r--r--vdslib/src/tests/distribution/testdata/distbit27.java.results510
-rw-r--r--vdslib/src/tests/distribution/testdata/distbit28.java.results510
-rw-r--r--vdslib/src/tests/distribution/testdata/distbit29.java.results510
-rw-r--r--vdslib/src/tests/distribution/testdata/distbit3.java.results510
-rw-r--r--vdslib/src/tests/distribution/testdata/distbit30.java.results510
-rw-r--r--vdslib/src/tests/distribution/testdata/distbit31.java.results510
-rw-r--r--vdslib/src/tests/distribution/testdata/distbit32.java.results510
-rw-r--r--vdslib/src/tests/distribution/testdata/distbit4.java.results510
-rw-r--r--vdslib/src/tests/distribution/testdata/distbit5.java.results510
-rw-r--r--vdslib/src/tests/distribution/testdata/distbit6.java.results510
-rw-r--r--vdslib/src/tests/distribution/testdata/distbit7.java.results510
-rw-r--r--vdslib/src/tests/distribution/testdata/distbit8.java.results510
-rw-r--r--vdslib/src/tests/distribution/testdata/distbit9.java.results510
-rw-r--r--vdslib/src/tests/distribution/testdata/down.java.results730
-rw-r--r--vdslib/src/tests/distribution/testdata/group-capacity.java.results4510
-rw-r--r--vdslib/src/tests/distribution/testdata/hierarchical-grouping-deep.java.results730
-rw-r--r--vdslib/src/tests/distribution/testdata/hierarchical-grouping-distributor-notakeover.java.results730
-rw-r--r--vdslib/src/tests/distribution/testdata/hierarchical-grouping-distributor-takeover.java.results730
-rw-r--r--vdslib/src/tests/distribution/testdata/hierarchical-grouping.java.results730
-rw-r--r--vdslib/src/tests/distribution/testdata/java_capacity.cfg46
-rw-r--r--vdslib/src/tests/distribution/testdata/java_capacity.distribution8955
-rw-r--r--vdslib/src/tests/distribution/testdata/java_capacity.state1
-rw-r--r--vdslib/src/tests/distribution/testdata/java_depth2.cfg30
-rw-r--r--vdslib/src/tests/distribution/testdata/java_depth2.distribution5373
-rw-r--r--vdslib/src/tests/distribution/testdata/java_depth2.state1
-rw-r--r--vdslib/src/tests/distribution/testdata/java_depth3.cfg46
-rw-r--r--vdslib/src/tests/distribution/testdata/java_depth3.distribution8955
-rw-r--r--vdslib/src/tests/distribution/testdata/java_depth3.state1
-rw-r--r--vdslib/src/tests/distribution/testdata/java_retired.cfg46
-rw-r--r--vdslib/src/tests/distribution/testdata/java_retired.distribution8955
-rw-r--r--vdslib/src/tests/distribution/testdata/java_retired.state1
-rw-r--r--vdslib/src/tests/distribution/testdata/minimal-movement.java.results730
-rw-r--r--vdslib/src/tests/distribution/testdata/simple.java.results730
-rw-r--r--vdslib/src/tests/state/.gitignore8
-rw-r--r--vdslib/src/tests/state/CMakeLists.txt7
-rw-r--r--vdslib/src/tests/state/clusterstatetest.cpp389
-rwxr-xr-xvdslib/src/tests/state/generate_plots.sh17
-rw-r--r--vdslib/src/tests/state/grouptest.cpp381
-rw-r--r--vdslib/src/tests/state/nodestatetest.cpp110
-rw-r--r--vdslib/src/tests/testrunner.cpp15
-rw-r--r--vdslib/src/tests/thread/.gitignore3
-rw-r--r--vdslib/src/tests/thread/CMakeLists.txt6
-rw-r--r--vdslib/src/tests/thread/taskschedulertest.cpp244
-rw-r--r--vdslib/src/vespa/vdslib/.gitignore3
-rw-r--r--vdslib/src/vespa/vdslib/CMakeLists.txt11
-rw-r--r--vdslib/src/vespa/vdslib/bucketdistribution.cpp115
-rw-r--r--vdslib/src/vespa/vdslib/bucketdistribution.h119
-rw-r--r--vdslib/src/vespa/vdslib/container/.gitignore2
-rw-r--r--vdslib/src/vespa/vdslib/container/CMakeLists.txt15
-rw-r--r--vdslib/src/vespa/vdslib/container/documentlist.cpp498
-rw-r--r--vdslib/src/vespa/vdslib/container/documentlist.h250
-rw-r--r--vdslib/src/vespa/vdslib/container/documentsummary.cpp88
-rw-r--r--vdslib/src/vespa/vdslib/container/documentsummary.h63
-rw-r--r--vdslib/src/vespa/vdslib/container/dummycppfile.cpp4
-rw-r--r--vdslib/src/vespa/vdslib/container/lruorder.h161
-rw-r--r--vdslib/src/vespa/vdslib/container/mutabledocumentlist.cpp223
-rw-r--r--vdslib/src/vespa/vdslib/container/mutabledocumentlist.h46
-rw-r--r--vdslib/src/vespa/vdslib/container/operationlist.cpp43
-rw-r--r--vdslib/src/vespa/vdslib/container/operationlist.h81
-rw-r--r--vdslib/src/vespa/vdslib/container/parameters.cpp152
-rw-r--r--vdslib/src/vespa/vdslib/container/parameters.h110
-rw-r--r--vdslib/src/vespa/vdslib/container/searchresult.cpp213
-rw-r--r--vdslib/src/vespa/vdslib/container/searchresult.h133
-rw-r--r--vdslib/src/vespa/vdslib/container/smallvector.h294
-rw-r--r--vdslib/src/vespa/vdslib/container/visitorordering.cpp15
-rw-r--r--vdslib/src/vespa/vdslib/container/visitorordering.h37
-rw-r--r--vdslib/src/vespa/vdslib/container/visitorstatistics.cpp43
-rw-r--r--vdslib/src/vespa/vdslib/container/visitorstatistics.h50
-rw-r--r--vdslib/src/vespa/vdslib/container/writabledocumentlist.cpp95
-rw-r--r--vdslib/src/vespa/vdslib/container/writabledocumentlist.h46
-rw-r--r--vdslib/src/vespa/vdslib/defs.h10
-rw-r--r--vdslib/src/vespa/vdslib/distribution/.gitignore3
-rw-r--r--vdslib/src/vespa/vdslib/distribution/CMakeLists.txt8
-rw-r--r--vdslib/src/vespa/vdslib/distribution/distribution.cpp675
-rw-r--r--vdslib/src/vespa/vdslib/distribution/distribution.h199
-rw-r--r--vdslib/src/vespa/vdslib/distribution/group.cpp200
-rw-r--r--vdslib/src/vespa/vdslib/distribution/group.h113
-rw-r--r--vdslib/src/vespa/vdslib/distribution/idealnodecalculator.h101
-rw-r--r--vdslib/src/vespa/vdslib/distribution/idealnodecalculatorcache.h162
-rw-r--r--vdslib/src/vespa/vdslib/distribution/idealnodecalculatorimpl.h64
-rw-r--r--vdslib/src/vespa/vdslib/distribution/redundancygroupdistribution.cpp149
-rw-r--r--vdslib/src/vespa/vdslib/distribution/redundancygroupdistribution.h51
-rw-r--r--vdslib/src/vespa/vdslib/state/.gitignore9
-rw-r--r--vdslib/src/vespa/vdslib/state/CMakeLists.txt11
-rw-r--r--vdslib/src/vespa/vdslib/state/clusterstate.cpp524
-rw-r--r--vdslib/src/vespa/vdslib/state/clusterstate.h82
-rw-r--r--vdslib/src/vespa/vdslib/state/diskstate.cpp165
-rw-r--r--vdslib/src/vespa/vdslib/state/diskstate.h50
-rw-r--r--vdslib/src/vespa/vdslib/state/idealgroup.cpp27
-rw-r--r--vdslib/src/vespa/vdslib/state/idealgroup.h61
-rw-r--r--vdslib/src/vespa/vdslib/state/node.cpp22
-rw-r--r--vdslib/src/vespa/vdslib/state/node.h41
-rw-r--r--vdslib/src/vespa/vdslib/state/nodestate.cpp613
-rw-r--r--vdslib/src/vespa/vdslib/state/nodestate.h108
-rw-r--r--vdslib/src/vespa/vdslib/state/nodetype.cpp36
-rw-r--r--vdslib/src/vespa/vdslib/state/nodetype.h54
-rw-r--r--vdslib/src/vespa/vdslib/state/random.h35
-rw-r--r--vdslib/src/vespa/vdslib/state/state.cpp87
-rw-r--r--vdslib/src/vespa/vdslib/state/state.h88
-rw-r--r--vdslib/src/vespa/vdslib/thread/.gitignore2
-rw-r--r--vdslib/src/vespa/vdslib/thread/CMakeLists.txt6
-rw-r--r--vdslib/src/vespa/vdslib/thread/taskscheduler.cpp223
-rw-r--r--vdslib/src/vespa/vdslib/thread/taskscheduler.h105
204 files changed, 143025 insertions, 0 deletions
diff --git a/vdslib/.gitignore b/vdslib/.gitignore
new file mode 100644
index 00000000000..96c62777acb
--- /dev/null
+++ b/vdslib/.gitignore
@@ -0,0 +1,5 @@
+target
+vdslib-lib.iml
+/pom.xml.build
+Makefile
+Testing
diff --git a/vdslib/CMakeLists.txt b/vdslib/CMakeLists.txt
new file mode 100644
index 00000000000..8ea2075d68b
--- /dev/null
+++ b/vdslib/CMakeLists.txt
@@ -0,0 +1,30 @@
+# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_define_module(
+ DEPENDS
+ fastos
+ vespalog
+ vespalib
+ staging_vespalib
+ config_cloudconfig
+ configdefinitions
+ document
+
+ LIBS
+ src/vespa/vdslib
+ src/vespa/vdslib/container
+ src/vespa/vdslib/distribution
+ src/vespa/vdslib/state
+ src/vespa/vdslib/thread
+
+ TEST_DEPENDS
+ vdstestlib
+ cppunit
+
+ TESTS
+ src/tests
+ src/tests/bucketdistribution
+ src/tests/container
+ src/tests/distribution
+ src/tests/state
+ src/tests/thread
+)
diff --git a/vdslib/OWNERS b/vdslib/OWNERS
new file mode 100644
index 00000000000..97c35339850
--- /dev/null
+++ b/vdslib/OWNERS
@@ -0,0 +1,2 @@
+vekterli
+dybdahl
diff --git a/vdslib/README b/vdslib/README
new file mode 100644
index 00000000000..c91e8237d37
--- /dev/null
+++ b/vdslib/README
@@ -0,0 +1 @@
+Development libraries related to VDS
diff --git a/vdslib/pom.xml b/vdslib/pom.xml
new file mode 100644
index 00000000000..994fe8ddf5e
--- /dev/null
+++ b/vdslib/pom.xml
@@ -0,0 +1,109 @@
+<?xml version="1.0"?>
+<!-- Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>com.yahoo.vespa</groupId>
+ <artifactId>parent</artifactId>
+ <version>6-SNAPSHOT</version>
+ <relativePath>../parent/pom.xml</relativePath>
+ </parent>
+ <artifactId>vdslib</artifactId>
+ <packaging>container-plugin</packaging>
+ <version>6-SNAPSHOT</version>
+ <name>vdslib</name>
+ <description> </description>
+ <dependencies>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.jettison</groupId>
+ <artifactId>jettison</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.yahoo.vespa</groupId>
+ <artifactId>config</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.yahoo.vespa</groupId>
+ <artifactId>document</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.yahoo.vespa</groupId>
+ <artifactId>configdefinitions</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>com.yahoo.vespa</groupId>
+ <artifactId>bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <compilerArgs>
+ <arg>-Xlint:all</arg>
+ <arg>-Xlint:-serial</arg>
+ </compilerArgs>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>javacc-maven-plugin</artifactId>
+ <version>2.6</version>
+ <executions>
+ <execution>
+ <id>javacc</id>
+ <goals>
+ <goal>javacc</goal>
+ </goals>
+ <configuration>
+ <lookAhead>1</lookAhead>
+ <isStatic>false</isStatic>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>com.yahoo.vespa</groupId>
+ <artifactId>config-class-plugin</artifactId>
+ <version>${project.version}</version>
+ <configuration>
+ <defFilesDirectories>src/vespa/vdslib/state/</defFilesDirectories>
+ </configuration>
+ <executions>
+ <execution>
+ <id>config-gen</id>
+ <goals>
+ <goal>config-gen</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-install-plugin</artifactId>
+ <version>2.3.1</version>
+ <configuration>
+ <updateReleaseInfo>true</updateReleaseInfo>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/vdslib/src/.gitignore b/vdslib/src/.gitignore
new file mode 100644
index 00000000000..1ba69e012b7
--- /dev/null
+++ b/vdslib/src/.gitignore
@@ -0,0 +1,4 @@
+Makefile.ini
+config_command.sh
+project.dsw
+/vdslib.mak
diff --git a/vdslib/src/main/java/com/yahoo/vdslib/BinaryDocumentList.java b/vdslib/src/main/java/com/yahoo/vdslib/BinaryDocumentList.java
new file mode 100644
index 00000000000..d2ccf2b2805
--- /dev/null
+++ b/vdslib/src/main/java/com/yahoo/vdslib/BinaryDocumentList.java
@@ -0,0 +1,55 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vdslib;
+
+import com.yahoo.document.DocumentTypeManager;
+import com.yahoo.vespa.objects.Serializer;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * @author <a href="mailto:einarmr@yahoo-inc.com">Einar M R Rosenvinge</a>
+ */
+class BinaryDocumentList extends DocumentList {
+
+ private DocumentTypeManager docMan;
+ private byte[] buffer;
+ private int docCount;
+
+ /**
+ * Create a new documentlist, using the given buffer.
+ *
+ * @param buffer buffer containing documents
+ */
+ BinaryDocumentList(DocumentTypeManager docMan, byte[] buffer) {
+ this.docMan = docMan;
+ ByteBuffer buf = ByteBuffer.wrap(buffer);
+ buf.order(ByteOrder.LITTLE_ENDIAN);
+ docCount = buf.getInt();
+ this.buffer = buffer;
+
+ }
+
+ @Override
+ public Entry get(int index) throws ArrayIndexOutOfBoundsException {
+ if (index < docCount) {
+ return Entry.create(docMan, buffer, index);
+ } else {
+ throw new ArrayIndexOutOfBoundsException(index + " >= " + docCount);
+ }
+ }
+
+ @Override
+ public int size() { return docCount; }
+
+ @Override
+ public int getApproxByteSize() {
+ return buffer.length;
+ }
+
+ @Override
+ public void serialize(Serializer buf) {
+ buf.put(null, buffer);
+ }
+
+}
diff --git a/vdslib/src/main/java/com/yahoo/vdslib/BinaryEntry.java b/vdslib/src/main/java/com/yahoo/vdslib/BinaryEntry.java
new file mode 100644
index 00000000000..4047a3ed4f0
--- /dev/null
+++ b/vdslib/src/main/java/com/yahoo/vdslib/BinaryEntry.java
@@ -0,0 +1,82 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vdslib;
+
+import com.yahoo.document.*;
+import com.yahoo.document.serialization.DocumentDeserializer;
+import com.yahoo.document.serialization.DocumentDeserializerFactory;
+import com.yahoo.io.GrowableByteBuffer;
+
+/**
+ * An entry in serialized form.
+ *
+ * @author <a href="mailto:thomasg@yahoo-inc.com">Thomas Gundersen</a>, <a href="mailto:einarmr@yahoo-inc.com">Einar M R Rosenvinge</a>
+ */
+class BinaryEntry extends Entry {
+ private MetaEntry metaEntry;
+ private byte[] buffer;
+ private DocumentTypeManager docMan;
+
+ /**
+ * Creates an entry from serialized form.
+ * @param docMan The documentmanager to use when deserializing.
+ * @param buffer the buffer to read the entry from
+ * @param entryIndex the index of the entry in the buffer
+ */
+ BinaryEntry(DocumentTypeManager docMan, byte[] buffer, int entryIndex) {
+ this.buffer = buffer;
+ metaEntry = new MetaEntry(buffer, 4 + entryIndex * MetaEntry.SIZE);
+ this.docMan = docMan;
+ }
+
+ @Override
+ public boolean valid() { return buffer != null; }
+
+ @Override
+ public boolean isRemoveEntry() { return (metaEntry.flags & MetaEntry.REMOVE_ENTRY) != 0; }
+
+ @Override
+ public boolean isBodyStripped() { return (metaEntry.flags & MetaEntry.BODY_STRIPPED) != 0; }
+
+ @Override
+ public boolean isUpdateEntry() { return (metaEntry.flags & MetaEntry.UPDATE_ENTRY) != 0; }
+
+ @Override
+ public long getTimestamp() { return metaEntry.timestamp; }
+
+ @Override
+ public DocumentOperation getDocumentOperation() {
+ DocumentDeserializer buf = DocumentDeserializerFactory.create42(
+ docMan,
+ GrowableByteBuffer.wrap(buffer, metaEntry.headerPos, metaEntry.headerLen),
+ (metaEntry.bodyLen > 0) ? GrowableByteBuffer.wrap(buffer, metaEntry.bodyPos, metaEntry.bodyLen) : null
+ );
+
+ DocumentOperation op;
+
+ if ((metaEntry.flags & MetaEntry.UPDATE_ENTRY) != 0) {
+ op = new DocumentUpdate(buf);
+ } else if ((metaEntry.flags & MetaEntry.REMOVE_ENTRY) != 0) {
+ op = new DocumentRemove(new Document(buf).getId());
+ } else {
+ op = new DocumentPut(new Document(buf));
+ ((DocumentPut) op).getDocument().setLastModified(getTimestamp());
+
+ }
+ return op;
+ }
+
+ @Override
+ public DocumentOperation getHeader() {
+ DocumentDeserializer buf = DocumentDeserializerFactory.create42(docMan, GrowableByteBuffer.wrap(buffer, metaEntry.headerPos, metaEntry.headerLen));
+ if ((metaEntry.flags & MetaEntry.UPDATE_ENTRY) != 0) {
+ return new DocumentUpdate(buf);
+ } else if ((metaEntry.flags & MetaEntry.REMOVE_ENTRY) != 0) {
+ return new DocumentRemove(new Document(buf).getId());
+ } else {
+ DocumentPut op = new DocumentPut(new Document(buf));
+ op.getDocument().setLastModified(getTimestamp());
+ return op;
+ }
+ }
+
+}
diff --git a/vdslib/src/main/java/com/yahoo/vdslib/BucketDistribution.java b/vdslib/src/main/java/com/yahoo/vdslib/BucketDistribution.java
new file mode 100644
index 00000000000..0e3e80b2542
--- /dev/null
+++ b/vdslib/src/main/java/com/yahoo/vdslib/BucketDistribution.java
@@ -0,0 +1,205 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vdslib;
+
+import com.yahoo.document.BucketId;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
+ */
+public class BucketDistribution {
+
+ // A logger object to enable proper logging.
+ private static Logger log = Logger.getLogger(BucketDistribution.class.getName());
+
+ // A map from bucket id to column index.
+ private int[] bucketToColumn;
+
+ // The number of columns to distribute to.
+ private int numColumns;
+
+ // The number of bits to use for bucket identification.
+ private int numBucketBits;
+
+ /**
+ * Constructs a new bucket distribution object with a given number of columns and buckets.
+ *
+ * @param numColumns The number of columns to distribute to.
+ * @param numBucketBits The number of bits to use for bucket id.
+ */
+ public BucketDistribution(int numColumns, int numBucketBits) {
+ this.numBucketBits = numBucketBits;
+ bucketToColumn = new int[getNumBuckets()];
+ reset();
+ setNumColumns(numColumns);
+ }
+
+ /**
+ * Constructs a new bucket distribution object as a copy of another.
+ *
+ * @param other The distribution object to copy.
+ */
+ public BucketDistribution(BucketDistribution other) {
+ bucketToColumn = other.bucketToColumn.clone();
+ numColumns = other.numColumns;
+ numBucketBits = other.numBucketBits;
+ }
+
+ /**
+ * Returns the number of buckets that the given number of bucket bits will allow.
+ *
+ * @param numBucketBits The number of bits to use for bucket id.
+ * @return The number of buckets allowed.
+ */
+ private static int getNumBuckets(int numBucketBits) {
+ return 1 << numBucketBits;
+ }
+
+ /**
+ * This method returns a list that contains the distributions of the given number of buckets over the given number
+ * of columns.
+ *
+ * @param numColumns The number of columns to distribute to.
+ * @param numBucketBits The number of bits to use for bucket id.
+ * @return The bucket distribution.
+ */
+ private static List<Integer> getBucketCount(int numColumns, int numBucketBits) {
+ List<Integer> ret = new ArrayList<Integer>(numColumns);
+ int cnt = getNumBuckets(numBucketBits) / numColumns;
+ int rst = getNumBuckets(numBucketBits) % numColumns;
+ for (int i = 0; i < numColumns; ++i) {
+ ret.add(cnt + (i < rst ? 1 : 0));
+ }
+ return ret;
+ }
+
+ /**
+ * This method returns a list similar to {@link com.yahoo.vdslib.BucketDistribution#getBucketCount(int, int)}, except that the returned list
+ * contains the number of buckets that will have to be migrated from each column if an additional column was added.
+ *
+ * @param numColumns The original number of columns.
+ * @param numBucketBits The number of bits to use for bucket id.
+ * @return The number of buckets to migrate, one value per column.
+ */
+ private static List<Integer> getBucketMigrateCount(int numColumns, int numBucketBits) {
+ List<Integer> ret = getBucketCount(numColumns++, numBucketBits);
+ int cnt = getNumBuckets(numBucketBits) / numColumns;
+ int rst = getNumBuckets(numBucketBits) % numColumns;
+ for (int i = 0; i < numColumns - 1; ++i) {
+ ret.set(i, ret.get(i) - (cnt + (i < rst ? 1 : 0)));
+ }
+ return ret;
+ }
+
+ /**
+ * Sets the number of columns to distribute to to 1, and resets the content of the internal bucket-to-column map so
+ * that it all buckets point to that single column.
+ */
+ public void reset() {
+ for (int i = 0; i < bucketToColumn.length; ++i) {
+ bucketToColumn[i] = 0;
+ }
+ numColumns = 1;
+ }
+
+ /**
+ * Adds a single column to this bucket distribution object. This will modify the internal bucket-to-column map so
+ * that it takes into account the new column.
+ */
+ private void addColumn() {
+ int newColumns = numColumns + 1;
+ List<Integer> migrate = getBucketMigrateCount(numColumns, numBucketBits);
+ int numBuckets = getNumBuckets(numBucketBits);
+ for (int i = 0; i < numBuckets; ++i) {
+ int old = bucketToColumn[i];
+ if (migrate.get(old) > 0) {
+ bucketToColumn[i] = numColumns; // move this bucket to the new column
+ migrate.set(old, migrate.get(old) - 1);
+ }
+ }
+ numColumns = newColumns;
+ }
+
+ /**
+ * Sets the number of columns to use for this document distribution object. This will reset and setup this object
+ * from scratch. The original number of buckets is maintained.
+ *
+ * @param numColumns The new number of columns to distribute to.
+ */
+ public synchronized void setNumColumns(int numColumns) {
+ if (numColumns < this.numColumns) {
+ reset();
+ }
+ if (numColumns == this.numColumns) {
+ return;
+ }
+ for (int i = numColumns - this.numColumns; --i >= 0; ) {
+ addColumn();
+ }
+ }
+
+ /**
+ * Returns the number of columns to distribute to.
+ *
+ * @return The number of columns.
+ */
+ public int getNumColumns() {
+ return numColumns;
+ }
+
+ /**
+ * Sets the number of buckets to use for this document distribution object. This will reset and setup this object
+ * from scratch. The original number of columns is maintained.
+ *
+ * @param numBucketBits The new number of bits to use for bucket id.
+ */
+ public synchronized void setNumBucketBits(int numBucketBits) {
+ if (numBucketBits == this.numBucketBits) {
+ return;
+ }
+ this.numBucketBits = numBucketBits;
+ bucketToColumn = new int[getNumBuckets(numBucketBits)];
+ int numColumns = this.numColumns;
+ reset();
+ setNumColumns(numColumns);
+ }
+
+ /**
+ * Returns the number of bits used for bucket identifiers.
+ *
+ * @return The number of bits.
+ */
+ public int getNumBucketBits() {
+ return numBucketBits;
+ }
+
+ /**
+ * Returns the number of buckets available using the configured number of bucket bits.
+ *
+ * @return The number of buckets.
+ */
+ public int getNumBuckets() {
+ return getNumBuckets(numBucketBits);
+ }
+
+ /**
+ * This method maps the given bucket id to its corresponding column.
+ *
+ * @param bucketId The bucket whose column to lookup.
+ * @return The column to distribute the bucket to.
+ */
+ public int getColumn(BucketId bucketId) {
+ int ret = (int)(bucketId.getId() & (getNumBuckets(numBucketBits) - 1));
+ if (ret >= bucketToColumn.length) {
+ log.log(Level.SEVERE,
+ "The bucket distribution map is not in sync with the number of bucket bits. " +
+ "This should never happen! Distribution is broken!!");
+ return 0;
+ }
+ return bucketToColumn[ret];
+ }
+}
diff --git a/vdslib/src/main/java/com/yahoo/vdslib/DocumentList.java b/vdslib/src/main/java/com/yahoo/vdslib/DocumentList.java
new file mode 100644
index 00000000000..cbe5de78b76
--- /dev/null
+++ b/vdslib/src/main/java/com/yahoo/vdslib/DocumentList.java
@@ -0,0 +1,108 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vdslib;
+
+import com.yahoo.document.DocumentId;
+import com.yahoo.document.DocumentTypeManager;
+import com.yahoo.vespa.objects.Serializer;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public abstract class DocumentList {
+
+ protected DocumentList() { }
+
+ /**
+ * Creates a DocumentList from serialized form.
+ *
+ * @param docMan Documentmanager to use when deserializing
+ * @param buffer the buffer to read from
+ * @return a DocumentList instance
+ */
+ public static DocumentList create(DocumentTypeManager docMan, byte[] buffer) {
+ return new BinaryDocumentList(docMan, buffer);
+ }
+
+ /**
+ * Creates a DocumentList from a list of entries.
+ * @param entries the entries to create a DocumentList from
+ * @return a DocumentList instance
+ * @see com.yahoo.vdslib.Entry
+ */
+ public static DocumentList create(List<Entry> entries) {
+ return new DynamicDocumentList(entries);
+ }
+
+ /**
+ * Creates a DocumentList containing a single entry.
+ *
+ * @param entry the entry to create a DocumentList from
+ * @return a DocumentList instance
+ * @see com.yahoo.vdslib.Entry
+ */
+ public static DocumentList create(Entry entry) {
+ return new DynamicDocumentList(entry);
+ }
+
+ /**
+ * Retrieves the specified Entry from the list.
+ *
+ * @param index the index of the Entry to return (0-based)
+ * @return the entry at the specified position
+ * @throws ArrayIndexOutOfBoundsException if index is &lt; 0 or &gt; size()
+ * @throws com.yahoo.document.serialization.DeserializationException if the DocumentList is stored in binary form internally and deserialization fails
+ */
+ public abstract Entry get(int index) throws ArrayIndexOutOfBoundsException;
+
+ /**
+ * Returns the size of the list.
+ *
+ * @return the size of the list
+ */
+ public abstract int size();
+
+ /**
+ * Returns the byte size of the list. The value returned is exact if the list is stored in
+ * binary form internally, otherwise it is approximate.
+ *
+ * @return the byte size of the list
+ */
+ public abstract int getApproxByteSize();
+
+ /**
+ * Serialize the list into the given buffer.
+ *
+ * @param buf the buffer to serialize into
+ */
+ public abstract void serialize(Serializer buf);
+
+ /**
+ * Test if a contains b
+ *
+ * @param list DocumentList contained
+ * @return true if a contains b
+ */
+ public boolean containsAll(DocumentList list) {
+ if( this.size() < list.size()) {
+ return false;
+ }
+
+ Map<DocumentId, Integer> indexes = new HashMap<DocumentId, Integer>();
+ for (int i=0; i<this.size(); ++i) {
+ indexes.put(this.get(i).getDocumentOperation().getId(), i);
+ }
+ for (int i=0; i<list.size(); ++i) {
+ Integer index = indexes.get(list.get(i).getDocumentOperation().getId());
+ if (index == null ||
+ list.get(i).getTimestamp() != this.get(index).getTimestamp() ||
+ list.get(i).kind() != this.get(index).kind())
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+}
+
diff --git a/vdslib/src/main/java/com/yahoo/vdslib/DocumentSummary.java b/vdslib/src/main/java/com/yahoo/vdslib/DocumentSummary.java
new file mode 100644
index 00000000000..27ca82b46dd
--- /dev/null
+++ b/vdslib/src/main/java/com/yahoo/vdslib/DocumentSummary.java
@@ -0,0 +1,70 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vdslib;
+import com.yahoo.vespa.objects.BufferSerializer;
+import com.yahoo.vespa.objects.Deserializer;
+
+import java.nio.ByteOrder;
+import java.io.UnsupportedEncodingException;
+import java.lang.String;
+
+
+public class DocumentSummary {
+ public static class Summary implements Comparable<Summary> {
+ private String docId;
+ private byte [] summary;
+ private Summary(String docId) {
+ this.docId = docId;
+ }
+ public Summary(String docId, byte [] summary) {
+ this(docId);
+ this.summary = summary;
+ }
+ final public String getDocId() { return docId; }
+ final public byte [] getSummary() { return summary; }
+ final public void setSummary(byte [] summary) { this.summary = summary; }
+ public int compareTo(Summary s) {
+ return getDocId().compareTo(s.getDocId());
+ }
+ }
+
+ private Summary [] summaries;
+
+ public DocumentSummary(Deserializer buf) {
+ BufferSerializer bser = (BufferSerializer) buf; // This is a trick. This should be done in a different way.
+ bser.order(ByteOrder.BIG_ENDIAN);
+ int vacant4byteOldSeqId = buf.getInt(null);
+ int numSummaries = buf.getInt(null);
+ summaries = new Summary[numSummaries];
+ if (numSummaries > 0) {
+ int summaryBufferSize = buf.getInt(null);
+
+ byte[] cArr = bser.getBuf().array();
+ int start = bser.getBuf().arrayOffset() + bser.position();
+ bser.position(bser.position() + summaryBufferSize);
+ for(int i=0; i < numSummaries; i++) {
+ int summarySize = buf.getInt(null);
+ int end = start;
+ while (cArr[end++] != 0);
+ try {
+ byte [] sb = new byte [summarySize];
+ System.arraycopy(cArr, end, sb, 0, summarySize);
+ summaries[i] = new Summary(new String(cArr, start, end-start-1, "utf-8"), sb);
+ start = end + summarySize;
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException("UTF-8 apparently not supported");
+ }
+ }
+ }
+ }
+ /**
+ * Constructs a new message from a byte buffer.
+ *
+ * @param buffer A byte buffer that contains a serialized message.
+ */
+ public DocumentSummary(byte[] buffer) {
+ this(BufferSerializer.wrap(buffer));
+ }
+
+ final public int getSummaryCount() { return summaries.length; }
+ final public Summary getSummary(int hitNo) { return summaries[hitNo]; }
+}
diff --git a/vdslib/src/main/java/com/yahoo/vdslib/DynamicDocumentList.java b/vdslib/src/main/java/com/yahoo/vdslib/DynamicDocumentList.java
new file mode 100644
index 00000000000..dbc139352b0
--- /dev/null
+++ b/vdslib/src/main/java/com/yahoo/vdslib/DynamicDocumentList.java
@@ -0,0 +1,161 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vdslib;
+
+import com.yahoo.compress.CompressionType;
+import com.yahoo.document.*;
+import com.yahoo.document.serialization.DocumentSerializer;
+import com.yahoo.document.serialization.DocumentSerializerFactory;
+import com.yahoo.vespa.objects.Serializer;
+
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * A list of document operations.
+ *
+ * @author <a href="mailto:einarmr@yahoo-inc.com">Einar M R Rosenvinge</a>
+ */
+public class DynamicDocumentList extends DocumentList {
+ private List<Entry> entries;
+
+ DynamicDocumentList(List<Entry> entries) {
+ //the entries themselves are of course still modifiable, this is just an internal safeguard:
+ this.entries = Collections.unmodifiableList(entries);
+ }
+
+ DynamicDocumentList(Entry entry) {
+ List<Entry> list = new ArrayList<>(1);
+ list.add(entry);
+ BucketIdFactory factory = new BucketIdFactory();
+ //the entry itself is of course still modifiable, this is just an internal safeguard:
+ this.entries = Collections.unmodifiableList(list);
+ }
+
+ @Override
+ public Entry get(int index) throws ArrayIndexOutOfBoundsException {
+ return entries.get(index);
+ }
+
+ @Override
+ public int size() {
+ return entries.size();
+ }
+
+ @Override
+ public int getApproxByteSize() {
+ int size = 4;
+ for (Entry entry : entries) {
+ if (entry.getDocumentOperation() instanceof DocumentPut) {
+ Document doc = ((DocumentPut)entry.getDocumentOperation()).getDocument();
+ size += MetaEntry.SIZE + doc.getSerializedSize();
+ } else if (entry.getDocumentOperation() instanceof DocumentUpdate) {
+ //TODO: Implement getSerializedSize() for DocumentUpdate!!!
+ size += MetaEntry.SIZE + 1024;
+ } else if (entry.getDocumentOperation() instanceof DocumentRemove) {
+ //TODO: Implement getSerializedSize() for DocumentRemove!!!
+ size += MetaEntry.SIZE + 64;
+ }
+ }
+ return size;
+ }
+
+ @Override
+ public void serialize(Serializer buf) {
+ if (buf instanceof DocumentSerializer) {
+ serializeInternal((DocumentSerializer) buf);
+ } else {
+ DocumentSerializer serializer = DocumentSerializerFactory.create42();
+ serializeInternal(serializer);
+ serializer.getBuf().getByteBuffer().flip();
+ buf.put(null, serializer.getBuf().getByteBuffer());
+ }
+ }
+ private void serializeInternal(DocumentSerializer buf) {
+ ByteOrder originalOrder = buf.getBuf().order();
+ buf.getBuf().order(ByteOrder.LITTLE_ENDIAN);
+ //save the position before the size
+ int posAtBeginning = buf.getBuf().position();
+
+ //write the number of entries
+ buf.putInt(null, entries.size());
+
+ //create a list of metaentries, one for each entry
+ List<MetaEntry> metaEntries = new ArrayList<MetaEntry>(entries.size());
+
+ //jump past the meta block, we will serialize this afterwards when we know sizes and positions
+ byte[] bogusEntry = new byte[entries.size() * MetaEntry.SIZE];
+ buf.put(null, bogusEntry);
+
+ for (Entry entry : entries) {
+ MetaEntry metaEntry = new MetaEntry();
+ metaEntries.add(metaEntry);
+
+ // is this a remove? in that case, set this flag
+ if (entry.isRemoveEntry()) metaEntry.flags |= MetaEntry.REMOVE_ENTRY;
+ // is the body stripped? in that case, set this flag
+ if (entry.isBodyStripped()) metaEntry.flags |= MetaEntry.BODY_STRIPPED;
+ // is this an update? in that case, set this flag
+ if (entry.getDocumentOperation() instanceof DocumentUpdate) metaEntry.flags |= MetaEntry.UPDATE_ENTRY;
+ // is this a document? in that case, try to set the timestamp
+ if (entry.getDocumentOperation() instanceof DocumentPut) {
+ Document doc = ((DocumentPut)entry.getDocumentOperation()).getDocument();
+ Long lastModified = doc.getLastModified();
+ if (lastModified != null) {
+ metaEntry.timestamp = lastModified;
+ }
+
+ if (doc.getDataType().getHeaderType().getCompressionConfig() != null
+ && doc.getDataType().getHeaderType().getCompressionConfig().type != CompressionType.NONE) {
+ metaEntry.flags |= MetaEntry.COMPRESSED;
+ }
+ if (doc.getDataType().getBodyType().getCompressionConfig() != null
+ && doc.getDataType().getBodyType().getCompressionConfig().type != CompressionType.NONE) {
+ metaEntry.flags |= MetaEntry.COMPRESSED;
+ }
+ }
+
+ metaEntry.headerPos = buf.getBuf().position() - posAtBeginning;
+
+ buf.getBuf().order(ByteOrder.BIG_ENDIAN);
+ if (entry.getDocumentOperation() instanceof DocumentPut) {
+ Document doc = ((DocumentPut)entry.getDocumentOperation()).getDocument();
+ //serialize document and save length:
+ doc.serializeHeader(buf);
+ } else if (entry.getDocumentOperation() instanceof DocumentUpdate) {
+ DocumentUpdate docUp = (DocumentUpdate) entry.getDocumentOperation();
+ docUp.serialize(buf);
+ } else if (entry.getDocumentOperation() instanceof DocumentRemove) {
+ new Document(DataType.DOCUMENT, entry.getDocumentOperation().getId()).serialize(buf);
+ } else {
+ throw new IllegalArgumentException("Can not handle class " + entry.getDocumentOperation().getClass().getName());
+ }
+
+ metaEntry.headerLen = buf.getBuf().position() - metaEntry.headerPos - posAtBeginning;
+
+ if (entry.getDocumentOperation() instanceof DocumentPut) {
+ metaEntry.bodyPos = buf.getBuf().position() - posAtBeginning;
+ Document doc = ((DocumentPut)entry.getDocumentOperation()).getDocument();
+ doc.serializeBody(buf);
+ metaEntry.bodyLen = buf.getBuf().position() - metaEntry.bodyPos - posAtBeginning;
+ } else {
+ metaEntry.bodyPos = 0;
+ metaEntry.bodyLen = 0;
+ }
+ buf.getBuf().order(ByteOrder.LITTLE_ENDIAN);
+
+ }
+ //save position after payload:
+ int posAfterEntries = buf.getBuf().position();
+ //go to beginning (after length) to serialize metaentries:
+ buf.getBuf().position(posAtBeginning + 4);
+ //serialize metaentries
+ for (MetaEntry metaEntry : metaEntries) {
+ metaEntry.serialize(buf.getBuf());
+ }
+ //set position to after payload:
+ buf.getBuf().position(posAfterEntries);
+ buf.getBuf().order(originalOrder);
+ }
+}
diff --git a/vdslib/src/main/java/com/yahoo/vdslib/DynamicEntry.java b/vdslib/src/main/java/com/yahoo/vdslib/DynamicEntry.java
new file mode 100644
index 00000000000..2aac8e711fc
--- /dev/null
+++ b/vdslib/src/main/java/com/yahoo/vdslib/DynamicEntry.java
@@ -0,0 +1,75 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vdslib;
+
+import com.yahoo.document.DocumentOperation;
+import com.yahoo.document.DocumentPut;
+import com.yahoo.document.DocumentRemove;
+import com.yahoo.document.DocumentUpdate;
+
+/**
+ * Represents an in-memory entry.
+ *
+ * @author <a href="mailto:einarmr@yahoo-inc.com">Einar M R Rosenvinge</a>
+ */
+class DynamicEntry extends Entry {
+ private DocumentOperation op;
+ private boolean bodyStripped;
+
+ DynamicEntry(DocumentOperation op, boolean bodyStripped) {
+ this.op = op;
+ this.bodyStripped = bodyStripped;
+ }
+
+ DynamicEntry(DocumentUpdate op) {
+ this.op = op;
+ this.bodyStripped = false;
+ }
+
+ DynamicEntry(DocumentRemove op) {
+ this.op = op;
+ this.bodyStripped = false;
+ }
+
+ @Override
+ public boolean valid() {
+ return true;
+ }
+
+ @Override
+ public boolean isRemoveEntry() {
+ return op instanceof DocumentRemove;
+ }
+
+ @Override
+ public boolean isBodyStripped() {
+ return bodyStripped;
+ }
+
+ @Override
+ public boolean isUpdateEntry() {
+ return op instanceof DocumentUpdate;
+ }
+
+ @Override
+ public long getTimestamp() {
+ if (op instanceof DocumentPut) {
+ DocumentPut put = (DocumentPut) op;
+ final Long lastModified = put.getDocument().getLastModified();
+ if (lastModified != null) {
+ return lastModified;
+ }
+ }
+ return 0L;
+ }
+
+ @Override
+ public DocumentOperation getDocumentOperation() {
+ return op;
+ }
+
+ @Override
+ public DocumentOperation getHeader() {
+ return op;
+ //TODO: Only return header fields of Document here...?
+ }
+}
diff --git a/vdslib/src/main/java/com/yahoo/vdslib/Entry.java b/vdslib/src/main/java/com/yahoo/vdslib/Entry.java
new file mode 100644
index 00000000000..8674db00419
--- /dev/null
+++ b/vdslib/src/main/java/com/yahoo/vdslib/Entry.java
@@ -0,0 +1,159 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vdslib;
+
+import com.yahoo.document.DocumentOperation;
+import com.yahoo.document.DocumentRemove;
+import com.yahoo.document.DocumentTypeManager;
+import com.yahoo.document.DocumentUpdate;
+
+/**
+ * Represents a document operation in a DocumentList, which can currently be
+ * PUT, REMOVE and UPDATE.
+ *
+ * @author <a href="mailto:thomasg@yahoo-inc.com">Thomas Gundersen</a>, <a href="mailto:einarmr@yahoo-inc.com">Einar M R Rosenvinge</a>
+ */
+public abstract class Entry {
+
+ protected Entry() { }
+
+ /**
+ * Creates a new entry from serialized form.
+ *
+ * @param docMan Documentmanager to use when deserializing
+ * @param buffer the buffer to read the entry from
+ * @param entryIndex the index of the entry in the buffer
+ * @return an Entry reading from the buffer
+ */
+ public static Entry create(DocumentTypeManager docMan, byte[] buffer, int entryIndex) {
+ return new BinaryEntry(docMan, buffer, entryIndex);
+ }
+
+ /**
+ * Creates a new entry from a document operation.
+ *
+ * @param op the document in the entry
+ * @param bodyStripped true if the document contains only header fields
+ * @return an Entry for this document
+ */
+ public static Entry create(DocumentOperation op, boolean bodyStripped) {
+ return new DynamicEntry(op, bodyStripped);
+ }
+
+ /**
+ * Creates a new entry from a document operation.
+ *
+ * @param op the document in the entry
+ * @return an Entry for this document
+ */
+ public static Entry create(DocumentOperation op) {
+ return create(op, false);
+ }
+ /**
+ * Creates a new entry from a document remove operation.
+ *
+ * @param doc the document in the entry
+ * @return an Entry for this document
+ */
+ public static Entry create(DocumentRemove doc) {
+ return new DynamicEntry(doc);
+ }
+
+ /**
+ * Creates a new entry from a document update operation.
+ *
+ * @param doc the document update in the entry
+ * @return an Entry for this document update
+ */
+ public static Entry create(DocumentUpdate doc) {
+ return new DynamicEntry(doc);
+ }
+
+ /**
+ * Entries in iterators gotten from DocumentList::end() are invalid.
+ * @return true if valid
+ */
+ public abstract boolean valid();
+
+ /**
+ * Returns true if the Document represented by this entry has been removed from persistent storage.
+ *
+ * @return true if the Document has been removed
+ */
+ public abstract boolean isRemoveEntry();
+
+ /**
+ * Returns true if the Document represented by this entry has gotten its body fields stripped
+ * away (note: the body fields might still be stored in persistent storage).
+ *
+ * @return true if the Document only has header fields
+ */
+ public abstract boolean isBodyStripped();
+
+ /**
+ * Returns true if this entry represents a document update operation.
+ *
+ * @return true if this is a document update operation
+ */
+ public abstract boolean isUpdateEntry();
+
+
+ public int kind(){
+ if (isRemoveEntry()) {
+ return 0; //REMOVE
+ }
+ if (isUpdateEntry()) {
+ return 2; //UPDATE
+ }
+ return 1; // PUT
+ }
+
+ /**
+ * Returns the timestamp (last modified) of this entry, from persistent storage.
+ * @return the last modified timestamp of this entry
+ */
+ public abstract long getTimestamp();
+
+ /**
+ * Returns the DocumentPut or DocumentUpdate operation in this entry.
+ *
+ * @return the DocumentOperation in this entry.
+ */
+ public abstract DocumentOperation getDocumentOperation();
+
+ /**
+ * Returns the Document header (if this is a DocumentPut or a DocumentRemove operation), otherwise
+ * a DocumentUpdate operation.
+ *
+ * @return a DocumentPut operation containing a Document with only the header fields present
+ * @throws RuntimeException if deserialization fails, or if this is a DocumentUpdate operation
+ */
+ public abstract DocumentOperation getHeader();
+
+ @Override
+ public boolean equals(Object obj) {
+ if ( this == obj ) {
+ return true;
+ }
+ if (!(obj instanceof Entry)) {
+ return false;
+ }
+ Entry entry = (Entry) obj;
+ return this.getDocumentOperation().getId().equals(entry.getDocumentOperation().getId()) &&
+ this.getTimestamp() == entry.getTimestamp() &&
+ this.kind() == entry.kind() &&
+ this.isBodyStripped() == entry.isBodyStripped() &&
+ this.valid() == entry.valid();
+ }
+
+ @Override
+ public int hashCode() {
+ int res = 31;
+ res = 31 * res + getDocumentOperation().getId().hashCode();
+ res = (int) (31 * res + getTimestamp());
+ res = 31 * res + kind()*31;
+ res = 31 * res + (isBodyStripped() ? 17 : 249);
+ res = 31 * res + (valid() ? 333 : 31);
+
+ return res;
+ }
+}
diff --git a/vdslib/src/main/java/com/yahoo/vdslib/MetaEntry.java b/vdslib/src/main/java/com/yahoo/vdslib/MetaEntry.java
new file mode 100644
index 00000000000..2e5022bba53
--- /dev/null
+++ b/vdslib/src/main/java/com/yahoo/vdslib/MetaEntry.java
@@ -0,0 +1,52 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vdslib;
+
+import com.yahoo.io.GrowableByteBuffer;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+public class MetaEntry {
+ public static int REMOVE_ENTRY = 1;
+ public static int BODY_STRIPPED = 2;
+ public static int BODY_IN_HEADER = 4;
+ public static int UPDATE_ENTRY = 8;
+ public static int COMPRESSED = 16;
+
+ public static int SIZE = 32;
+
+ public long timestamp = 0;
+ public int headerPos = 0;
+ public int headerLen = 0;
+ public int bodyPos = 0;
+ public int bodyLen = 0;
+ public byte flags = 0;
+
+ public MetaEntry() {
+ }
+
+ public MetaEntry(byte[] buffer, int position) {
+ ByteBuffer buf = ByteBuffer.wrap(buffer, position, SIZE);
+ buf.order(ByteOrder.LITTLE_ENDIAN);
+
+ timestamp = buf.getLong();
+ headerPos = buf.getInt();
+ headerLen = buf.getInt();
+ bodyPos = buf.getInt();
+ bodyLen = buf.getInt();
+ flags = buf.get();
+ }
+
+ public void serialize(GrowableByteBuffer buf) {
+ ByteOrder originalOrder = buf.order();
+ buf.order(ByteOrder.LITTLE_ENDIAN);
+ buf.putLong(timestamp); // 8
+ buf.putInt(headerPos); // 12
+ buf.putInt(headerLen); // 16
+ buf.putInt(bodyPos); // 20
+ buf.putInt(bodyLen); // 24
+ buf.putInt(flags); // 28 (written as little-endian int, this is on purpose)
+ buf.putInt(0); // 32
+ buf.order(originalOrder);
+ }
+}
diff --git a/vdslib/src/main/java/com/yahoo/vdslib/SearchResult.java b/vdslib/src/main/java/com/yahoo/vdslib/SearchResult.java
new file mode 100644
index 00000000000..e09fa6f460a
--- /dev/null
+++ b/vdslib/src/main/java/com/yahoo/vdslib/SearchResult.java
@@ -0,0 +1,119 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vdslib;
+import com.yahoo.vespa.objects.BufferSerializer;
+import com.yahoo.vespa.objects.Deserializer;
+
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteOrder;
+import java.util.Map;
+import java.util.TreeMap;
+
+public class SearchResult {
+ public static class Hit implements Comparable<Hit> {
+ private String docId;
+ private double rank;
+ public Hit(Hit h) {
+ docId = h.docId;
+ rank = h.rank;
+ }
+ public Hit(String docId, double rank) {
+ this.rank = rank;
+ this.docId = docId;
+ }
+ final public String getDocId() { return docId; }
+ final public double getRank() { return rank; }
+ final public void setRank(double rank) { this.rank = rank; }
+ public int compareTo(Hit h) {
+ return (h.rank < rank) ? -1 : (h.rank > rank) ? 1 : 0; // Sort order: descending
+ }
+ }
+ public static class HitWithSortBlob extends Hit {
+ private byte [] sortBlob;
+ public HitWithSortBlob(Hit h, byte [] sb) {
+ super(h);
+ sortBlob = sb;
+ }
+ final public byte [] getSortBlob() { return sortBlob; }
+ public int compareTo(Hit h) {
+ HitWithSortBlob b = (HitWithSortBlob) h;
+ int m = java.lang.Math.min(sortBlob.length, b.sortBlob.length);
+ for (int i = 0; i < m; i++) {
+ if (sortBlob[i] != b.sortBlob[i]) {
+ return (((int)sortBlob[i]) & 0xff) < (((int)b.sortBlob[i]) & 0xff) ? -1 : 1;
+ }
+ }
+ return sortBlob.length - b.sortBlob.length;
+ }
+ }
+ private int totalHits;
+ private Hit[] hits;
+ private TreeMap<Integer, byte []> aggregatorList;
+ private TreeMap<Integer, byte []> groupingList;
+
+ public SearchResult(Deserializer buf) {
+ BufferSerializer bser = (BufferSerializer) buf; // TODO: dirty cast. must do this differently
+ bser.order(ByteOrder.BIG_ENDIAN);
+ this.totalHits = buf.getInt(null);
+ int numHits = buf.getInt(null);
+ hits = new Hit[numHits];
+ if (numHits != 0) {
+ int docIdBufferLength = buf.getInt(null);
+ byte[] cArr = bser.getBuf().array();
+ int start = bser.getBuf().arrayOffset() + bser.position();
+ for(int i=0; i < numHits; i++) {
+ int end = start;
+ while (cArr[end++] != 0);
+ try {
+ hits[i] = new Hit(new String(cArr, start, end-start-1, "utf-8"), 0);
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException("UTF-8 apparently not supported");
+ }
+ start = end;
+ }
+ bser.position(start - bser.getBuf().arrayOffset());
+ for(int i=0; i < numHits; i++) {
+ hits[i].setRank(buf.getDouble(null));
+ }
+ }
+
+ int numSortBlobs = buf.getInt(null);
+ int [] size = new int [numSortBlobs];
+ for (int i = 0; i < numSortBlobs; i++) {
+ size[i] = buf.getInt(null);
+ }
+ for (int i = 0; i < numSortBlobs; i++) {
+ hits[i] = new HitWithSortBlob(hits[i], buf.getBytes(null, size[i]));
+ }
+
+ int numAggregators = buf.getInt(null);
+ aggregatorList = new TreeMap<Integer, byte []>();
+ for (int i = 0; i < numAggregators; i++) {
+ int aggrId = buf.getInt(null);
+ int aggrLength = buf.getInt(null);
+ aggregatorList.put(aggrId, buf.getBytes(null, aggrLength));
+ }
+
+ int numGroupings = buf.getInt(null);
+ groupingList = new TreeMap<Integer, byte []>();
+ for (int i = 0; i < numGroupings; i++) {
+ int aggrId = buf.getInt(null);
+ int aggrLength = buf.getInt(null);
+ groupingList.put(aggrId, buf.getBytes(null, aggrLength));
+ }
+
+ }
+ /**
+ * Constructs a new message from a byte buffer.
+ *
+ * @param buffer A byte buffer that contains a serialized message.
+ */
+ public SearchResult(byte[] buffer) {
+ this(BufferSerializer.wrap(buffer));
+ }
+
+ final public int getHitCount() { return hits.length; }
+ final public int getTotalHitCount() { return (totalHits != 0) ? totalHits : getHitCount(); }
+ final public Hit getHit(int hitNo) { return hits[hitNo]; }
+ final public Map<Integer, byte []> getAggregatorList() { return aggregatorList; }
+ final public Map<Integer, byte []> getGroupingList() { return groupingList; }
+}
diff --git a/vdslib/src/main/java/com/yahoo/vdslib/VisitorOrdering.java b/vdslib/src/main/java/com/yahoo/vdslib/VisitorOrdering.java
new file mode 100644
index 00000000000..cd543caa7f1
--- /dev/null
+++ b/vdslib/src/main/java/com/yahoo/vdslib/VisitorOrdering.java
@@ -0,0 +1,40 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vdslib;
+
+public class VisitorOrdering {
+ public static int ASCENDING = 0;
+ public static int DESCENDING = 1;
+
+ public int order;
+ public long orderingStart;
+ public short widthBits;
+ public short divisionBits;
+
+ public VisitorOrdering() {
+ this(ASCENDING, (long)0, (short)0, (short)0);
+ }
+
+ public VisitorOrdering(int order) {
+ this(order, (long)0, (short)0, (short)0);
+ }
+
+ public VisitorOrdering(int order, long orderingStart, short widthBits, short divisionBits) {
+ this.order = order;
+ this.orderingStart = orderingStart;
+ this.widthBits = widthBits;
+ this.divisionBits = divisionBits;
+ }
+
+ public int getOrder() { return order; }
+ public long getOrderingStart() { return orderingStart; }
+ public short getWidthBits() { return widthBits; }
+ public short getDivisionBits() { return divisionBits; }
+
+ public String toString() {
+ String out = (order == ASCENDING ? "+" : "-") +
+ "," + widthBits +
+ "," + divisionBits +
+ "," + orderingStart;
+ return out;
+ }
+}
diff --git a/vdslib/src/main/java/com/yahoo/vdslib/VisitorStatistics.java b/vdslib/src/main/java/com/yahoo/vdslib/VisitorStatistics.java
new file mode 100644
index 00000000000..906eb0db58d
--- /dev/null
+++ b/vdslib/src/main/java/com/yahoo/vdslib/VisitorStatistics.java
@@ -0,0 +1,57 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vdslib;
+
+public class VisitorStatistics {
+ int bucketsVisited = 0;
+ long documentsVisited = 0;
+ long bytesVisited = 0;
+ long documentsReturned = 0;
+ long bytesReturned = 0;
+ long secondPassDocumentsReturned = 0;
+ long secondPassBytesReturned = 0;
+
+ public void add(VisitorStatistics other) {
+ bucketsVisited += other.bucketsVisited;
+ documentsVisited += other.documentsVisited;
+ bytesVisited += other.bytesVisited;
+ documentsReturned += other.documentsReturned;
+ bytesReturned += other.bytesReturned;
+ secondPassDocumentsReturned += other.secondPassDocumentsReturned;
+ secondPassBytesReturned += other.secondPassBytesReturned;
+ }
+
+ public int getBucketsVisited() { return bucketsVisited; }
+ public void setBucketsVisited(int bucketsVisited) { this.bucketsVisited = bucketsVisited; }
+
+ public long getDocumentsVisited() { return documentsVisited; }
+ public void setDocumentsVisited(long documentsVisited) { this.documentsVisited = documentsVisited; }
+
+ public long getBytesVisited() { return bytesVisited; }
+ public void setBytesVisited(long bytesVisited) { this.bytesVisited = bytesVisited; }
+
+ public long getDocumentsReturned() { return documentsReturned; }
+ public void setDocumentsReturned(long documentsReturned) { this.documentsReturned = documentsReturned; }
+
+ public long getBytesReturned() { return bytesReturned; }
+ public void setBytesReturned(long bytesReturned) { this.bytesReturned = bytesReturned; }
+
+ public long getSecondPassDocumentsReturned() { return secondPassDocumentsReturned; }
+ public void setSecondPassDocumentsReturned(long secondPassDocumentsReturned) { this.secondPassDocumentsReturned = secondPassDocumentsReturned; }
+
+ public long getSecondPassBytesReturned() { return secondPassBytesReturned; }
+ public void setSecondPassBytesReturned(long secondPassBytesReturned) { this.secondPassBytesReturned = secondPassBytesReturned; }
+
+ public String toString() {
+ String out =
+ "Buckets visited: " + bucketsVisited + "\n" +
+ "Documents visited: " + documentsVisited + "\n" +
+ "Bytes visited: " + bytesVisited + "\n" +
+ "Documents returned: " + documentsReturned + "\n" +
+ "Bytes returned: " + bytesReturned + "\n" +
+ "Documents returned (2nd pass): " + secondPassDocumentsReturned + "\n" +
+ "Bytes returned (2nd pass): " + secondPassBytesReturned + "\n";
+
+ return out;
+ }
+
+}
diff --git a/vdslib/src/main/java/com/yahoo/vdslib/distribution/ConfiguredNode.java b/vdslib/src/main/java/com/yahoo/vdslib/distribution/ConfiguredNode.java
new file mode 100644
index 00000000000..dd0ad29f16b
--- /dev/null
+++ b/vdslib/src/main/java/com/yahoo/vdslib/distribution/ConfiguredNode.java
@@ -0,0 +1,42 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vdslib.distribution;
+
+/**
+ * A node configured to exist, with its configured node specific information.
+ * This is immutable. The identity and natural order of a node is its index.
+ *
+ * @author bratseth
+ */
+public class ConfiguredNode implements Comparable<ConfiguredNode> {
+
+ private final int index;
+
+ private final boolean retired;
+
+ public ConfiguredNode(int index, boolean retired) {
+ this.index = index;
+ this.retired = retired;
+ }
+
+ /** Return the index (distribution key) of this node */
+ public int index() { return index; }
+
+ /** Returns whether the node is configured to be retired */
+ public boolean retired() { return retired; }
+
+ @Override
+ public int hashCode() { return index; }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) return true;
+ if ( ! (other instanceof ConfiguredNode)) return false;
+ return ((ConfiguredNode)other).index == this.index;
+ }
+
+ @Override
+ public int compareTo(ConfiguredNode other) {
+ return Integer.compare(this.index, other.index);
+ }
+
+}
diff --git a/vdslib/src/main/java/com/yahoo/vdslib/distribution/Distribution.java b/vdslib/src/main/java/com/yahoo/vdslib/distribution/Distribution.java
new file mode 100644
index 00000000000..95b998b1ab5
--- /dev/null
+++ b/vdslib/src/main/java/com/yahoo/vdslib/distribution/Distribution.java
@@ -0,0 +1,536 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vdslib.distribution;
+
+import com.yahoo.collections.BobHash;
+import com.yahoo.config.subscription.ConfigSubscriber;
+import com.yahoo.vespa.config.content.StorDistributionConfig;
+import com.yahoo.config.subscription.ConfigSourceSet;
+import com.yahoo.vdslib.state.*;
+import com.yahoo.document.BucketId;
+
+import java.util.*;
+import java.text.ParseException;
+
+public class Distribution {
+
+ private int[] distributionBitMasks = new int[65];
+ private Group nodeGraph;
+ private int redundancy;
+ private boolean distributorAutoOwnershipTransferOnWholeGroupDown = false;
+ private ConfigSubscriber configSub;
+
+ public Group getRootGroup() {
+ return nodeGraph;
+ }
+
+ public int getRedundancy() {
+ return redundancy;
+ }
+
+ private ConfigSubscriber.SingleSubscriber<StorDistributionConfig> configSubscriber = new ConfigSubscriber.SingleSubscriber<StorDistributionConfig>() {
+ private int[] getGroupPath(String path) {
+ if (path.equals("invalid")) { return new int[0]; }
+ StringTokenizer st = new StringTokenizer(path, ".");
+ int[] p = new int[st.countTokens()];
+ for (int i=0; i<p.length; ++i) {
+ p[i] = Integer.valueOf(st.nextToken());
+ }
+ return p;
+ }
+
+ @Override
+ public void configure(StorDistributionConfig config) {
+ try{
+ Group root = null;
+ for (int i=0; i<config.group().size(); ++i) {
+ StorDistributionConfig.Group cg = config.group().get(i);
+ int[] path = new int[0];
+ if (root != null) {
+ path = getGroupPath(cg.index());
+ }
+ boolean isLeafGroup = (cg.nodes().size() > 0);
+ Group group;
+ int index = (path.length == 0 ? 0 : path[path.length - 1]);
+ if (isLeafGroup) {
+ group = new Group(index, cg.name());
+ List<ConfiguredNode> nodes = new ArrayList<>();
+ for (StorDistributionConfig.Group.Nodes node : cg.nodes()) {
+ nodes.add(new ConfiguredNode(node.index(), node.retired()));
+ }
+ group.setNodes(nodes);
+ } else {
+ group = new Group(index, cg.name(), new Group.Distribution(cg.partitions(), config.redundancy()));
+ }
+ group.setCapacity(cg.capacity());
+ if (path.length == 0) {
+ root = group;
+ } else {
+ assert(root != null);
+ Group parent = root;
+ for (int j=0; j<path.length - 1; ++j) {
+ parent = parent.getSubgroups().get(path[j]);
+ }
+ parent.addSubGroup(group);
+ }
+ }
+ if (root == null) {
+ throw new IllegalStateException("Got config that did not "
+ + "specify even a root group. Need a root group at"
+ + "\nminimum:\n" + config.toString());
+ }
+ root.calculateDistributionHashValues();
+ Distribution.this.nodeGraph = root;
+ Distribution.this.redundancy = config.redundancy();
+ //Distribution.this.diskDistribution = config.disk_distribution();
+ distributorAutoOwnershipTransferOnWholeGroupDown = config.distributor_auto_ownership_transfer_on_whole_group_down();
+ } catch (ParseException e) {
+ throw (IllegalStateException) new IllegalStateException("Failed to parse config").initCause(e);
+ }
+ }
+ };
+
+ public Distribution(String configId) {
+ this(configId, null);
+ }
+ public Distribution(String configId, ConfigSourceSet configSources) {
+ int mask = 0;
+ for (int i=0; i<=64; ++i) {
+ distributionBitMasks[i] = mask;
+ mask = (mask << 1) | 1;
+ }
+ if (configSources==null) {
+ configSub = new ConfigSubscriber();
+ } else {
+ configSub = new ConfigSubscriber(configSources);
+ }
+ configSub.subscribe(configSubscriber, StorDistributionConfig.class, configId);
+ }
+
+ public Distribution(StorDistributionConfig config) {
+ int mask = 0;
+ for (int i=0; i<=64; ++i) {
+ distributionBitMasks[i] = mask;
+ mask = (mask << 1) | 1;
+ }
+ configSubscriber.configure(config);
+ }
+
+ public void close() {
+ if (configSub!=null) configSub.close();
+ }
+
+ private int getGroupSeed(BucketId bucket, ClusterState state, Group group) {
+ int seed = ((int) bucket.getRawId()) & distributionBitMasks[state.getDistributionBitCount()];
+ seed ^= group.getDistributionHash();
+ return seed;
+ }
+
+ private int getDistributorSeed(BucketId bucket, ClusterState state) {
+ return ((int) bucket.getRawId()) & distributionBitMasks[state.getDistributionBitCount()];
+ }
+
+ private int getStorageSeed(BucketId bucket, ClusterState state) {
+ int seed = ((int) bucket.getRawId()) & distributionBitMasks[state.getDistributionBitCount()];
+
+ if (bucket.getUsedBits() > 33) {
+ int usedBits = bucket.getUsedBits() - 1;
+ seed ^= (distributionBitMasks[usedBits - 32]
+ & (bucket.getRawId() >> 32)) << 6;
+ }
+ return seed;
+ }
+
+ private class ScoredGroup implements Comparable<ScoredGroup> {
+ Group group;
+ double score;
+
+ ScoredGroup(Group g, double score) { this.group = g; this.score = score; }
+
+ @Override
+ public int compareTo(ScoredGroup o) {
+ // Sorts by highest first.
+ return new Double(o.score).compareTo(score);
+ }
+ }
+ private class ScoredNode {
+ int index;
+ int reliability;
+ double score;
+
+ ScoredNode(int index, int reliability, double score) { this.index = index; this.reliability = reliability; this.score = score; }
+ }
+ private static boolean allDistributorsDown(Group g, ClusterState clusterState) {
+ if (g.isLeafGroup()) {
+ for (ConfiguredNode node : g.getNodes()) {
+ NodeState ns = clusterState.getNodeState(new Node(NodeType.DISTRIBUTOR, node.index()));
+ if (ns.getState().oneOf("ui")) return false;
+ }
+ } else {
+ for (Group childGroup : g.getSubgroups().values()) {
+ if (!allDistributorsDown(childGroup, clusterState)) return false;
+ }
+ }
+ return true;
+ }
+ private Group getIdealDistributorGroup(BucketId bucket, ClusterState clusterState, Group parent, int redundancy) {
+ if (parent.isLeafGroup()) return parent;
+ int[] redundancyArray = parent.getDistribution().getRedundancyArray(redundancy);
+ TreeSet<ScoredGroup> results = new TreeSet<>();
+ int seed = getGroupSeed(bucket, clusterState, parent);
+ RandomGen random = new RandomGen(seed);
+ int currentIndex = 0;
+ for(Group g : parent.getSubgroups().values()) {
+ while (g.getIndex() < currentIndex++) random.nextDouble();
+ double score = random.nextDouble();
+ if (Math.abs(g.getCapacity() - 1.0) > 0.0000001) {
+ score = Math.pow(score, 1.0 / g.getCapacity());
+ }
+ results.add(new ScoredGroup(g, score));
+ }
+ if (distributorAutoOwnershipTransferOnWholeGroupDown) {
+ while (!results.isEmpty() && allDistributorsDown(results.first().group, clusterState)) {
+ results.remove(results.first());
+ }
+ }
+ if (results.isEmpty()) return null;
+ return getIdealDistributorGroup(bucket, clusterState, results.first().group, redundancyArray[0]);
+ }
+ private class ResultGroup implements Comparable<ResultGroup> {
+ Group group;
+ int redundancy;
+
+ ResultGroup(Group group, int redundancy) {
+ this.group = group;
+ this.redundancy = redundancy;
+ }
+
+ @Override
+ public int compareTo(ResultGroup o) {
+ return group.compareTo(o.group);
+ }
+ }
+ public void getIdealGroups(BucketId bucketId, ClusterState clusterState, Group parent,
+ int redundancy, List<ResultGroup> results) {
+ if (parent.isLeafGroup()) {
+ results.add(new ResultGroup(parent, redundancy));
+ return;
+ }
+
+ int[] redundancyArray = parent.getDistribution().getRedundancyArray(redundancy);
+
+ List<ScoredGroup> tmpResults = new ArrayList<>();
+ for (int i = 0; i < redundancyArray.length; ++i) {
+ tmpResults.add(new ScoredGroup(null, 0.0));
+ }
+
+ int seed = getGroupSeed(bucketId, clusterState, parent);
+
+ RandomGen random = new RandomGen(seed);
+
+ int currentIndex = 0;
+ Map<Integer, Group> subGroups = parent.getSubgroups();
+
+ for (Map.Entry<Integer, Group> group : subGroups.entrySet()) {
+ while (group.getKey() < currentIndex++) {
+ random.nextDouble();
+ }
+
+ double score = random.nextDouble();
+
+ if (group.getValue().getCapacity() != 1) {
+ score = Math.pow(score, 1.0 / group.getValue().getCapacity());
+ }
+
+ if (score > tmpResults.get(tmpResults.size() - 1).score) {
+ tmpResults.add(new ScoredGroup(group.getValue(), score));
+ Collections.sort(tmpResults);
+ tmpResults.remove(tmpResults.size() - 1);
+ }
+ }
+
+ for (int i = 0; i < tmpResults.size(); ++i) {
+ Group group = tmpResults.get(i).group;
+
+ if (group != null) {
+ getIdealGroups(bucketId, clusterState, group, redundancyArray[i], results);
+ }
+ }
+ }
+
+ private int getDiskSeed(BucketId bucket, int nodeIndex) {
+ // Assumes MODULO_BID for now.
+
+ long currentid = bucket.withoutCountBits();
+ byte[] ordered = new byte[8];
+ ordered[0] = (byte)(currentid >> (0*8));
+ ordered[1] = (byte)(currentid >> (1*8));
+ ordered[2] = (byte)(currentid >> (2*8));
+ ordered[3] = (byte)(currentid >> (3*8));
+ ordered[4] = (byte)(currentid >> (4*8));
+ ordered[5] = (byte)(currentid >> (5*8));
+ ordered[6] = (byte)(currentid >> (6*8));
+ ordered[7] = (byte)(currentid >> (7*8));
+ int initval = (1664525 * nodeIndex + 0xdeadbeef);
+ return BobHash.hash(ordered, initval);
+ }
+ /**
+ * This function should only depend on disk distribution and node index. It is
+ * assumed that any other change, for instance in hierarchical grouping, does
+ * not change disk index on disk.
+ */
+ int getIdealDisk(NodeState nodeState, int nodeIndex, BucketId bucket) {
+ // Catch special cases in a single if statement
+ if (nodeState.getDiskCount() < 2) {
+ if (nodeState.getDiskCount() == 1) {
+ return 0;
+ }
+ throw new IllegalArgumentException(
+ "Cannot pick ideal disk without knowing disk count.");
+ }
+
+ RandomGen randomizer = new RandomGen(getDiskSeed(bucket, nodeIndex));
+
+ double maxScore = 0.0;
+ int idealDisk = 0xffff;
+ for (int i=0, n=nodeState.getDiskCount(); i<n; ++i) {
+ double score = randomizer.nextDouble();
+ DiskState diskState = (nodeState.getDiskState(i));
+ if (diskState.getCapacity() != 1.0) {
+ score = Math.pow(score,
+ 1.0 / diskState.getCapacity());
+ }
+ if (score > maxScore) {
+ maxScore = score;
+ idealDisk = i;
+ }
+ }
+ return idealDisk;
+ }
+
+ public List<Integer> getIdealStorageNodes(ClusterState clusterState, BucketId bucket,
+ String upStates) throws TooFewBucketBitsInUseException {
+ List<Integer> resultNodes = new ArrayList<>();
+
+ // If bucket is split less than distribution bit, we cannot distribute
+ // it. Different nodes own various parts of the bucket.
+ if (bucket.getUsedBits() < clusterState.getDistributionBitCount()) {
+ String msg = "Cannot get ideal state for bucket " + bucket + " using "
+ + bucket.getUsedBits() + " bits when cluster uses "
+ + clusterState.getDistributionBitCount() + " distribution bits.";
+ throw new TooFewBucketBitsInUseException(msg);
+ }
+
+ // Find what hierarchical groups we should have copies in
+ List<ResultGroup> groupDistribution = new ArrayList<>();
+
+ getIdealGroups(bucket, clusterState, nodeGraph, redundancy, groupDistribution);
+
+ int seed = getStorageSeed(bucket, clusterState);
+
+ RandomGen random = new RandomGen(seed);
+ int randomIndex = 0;
+ for (ResultGroup group : groupDistribution) {
+ int redundancy = group.redundancy;
+ Collection<ConfiguredNode> nodes = group.group.getNodes();
+
+ // Create temporary place to hold results. Use double linked list
+ // for cheap access to back(). Stuff in redundancy fake entries to
+ // avoid needing to check size during iteration.
+ LinkedList<ScoredNode> tmpResults = new LinkedList<>();
+ for (int i = 0; i < redundancy; ++i) {
+ tmpResults.add(new ScoredNode(0, 0, 0.0));
+ }
+
+ for (ConfiguredNode configuredNode : nodes) {
+ NodeState nodeState = clusterState.getNodeState(new Node(NodeType.STORAGE, configuredNode.index()));
+ if (!nodeState.getState().oneOf(upStates)) {
+ continue;
+ }
+
+ if (nodeState.isAnyDiskDown()) {
+ int idealDiskIndex = getIdealDisk(nodeState, configuredNode.index(), bucket);
+ if (nodeState.getDiskState(idealDiskIndex).getState() != State.UP) {
+ continue;
+ }
+ }
+
+ // Get the score from the random number generator. Make sure we
+ // pick correct random number. Optimize for the case where we
+ // pick in rising order.
+ if (configuredNode.index() != randomIndex) {
+ if (configuredNode.index() < randomIndex) {
+ random.setSeed(seed);
+ randomIndex = 0;
+ }
+
+ for (int k = randomIndex; k < configuredNode.index(); ++k) {
+ random.nextDouble();
+ }
+
+ randomIndex = configuredNode.index();
+ }
+
+ double score = random.nextDouble();
+ ++randomIndex;
+ if (nodeState.getCapacity() != 1.0) {
+ score = Math.pow(score, 1.0 / nodeState.getCapacity());
+ }
+ if (score > tmpResults.getLast().score) {
+ for (int i = 0; i < tmpResults.size(); ++i) {
+ if (score > tmpResults.get(i).score) {
+ tmpResults.add(i, new ScoredNode(configuredNode.index(), nodeState.getReliability(), score));
+ break;
+ }
+ }
+ tmpResults.removeLast();
+ }
+ }
+
+ for (ScoredNode node : tmpResults) {
+ resultNodes.add(node.index);
+ }
+ }
+
+ return resultNodes;
+ }
+
+ public static class TooFewBucketBitsInUseException extends Exception {
+ public TooFewBucketBitsInUseException(String message) {
+ super(message);
+ }
+ }
+ public static class NoDistributorsAvailableException extends Exception {
+ public NoDistributorsAvailableException(String message) {
+ super(message);
+ }
+ }
+ public int getIdealDistributorNode(ClusterState state, BucketId bucket, String upStates) throws TooFewBucketBitsInUseException, NoDistributorsAvailableException {
+ if (bucket.getUsedBits() < state.getDistributionBitCount()) {
+ throw new TooFewBucketBitsInUseException("Cannot get ideal state for bucket " + bucket + " using " + bucket.getUsedBits()
+ + " bits when cluster uses " + state.getDistributionBitCount() + " distribution bits.");
+ }
+
+ Group idealGroup = getIdealDistributorGroup(bucket, state, nodeGraph, redundancy);
+ int seed = getDistributorSeed(bucket, state);
+ RandomGen random = new RandomGen(seed);
+ int randomIndex = 0;
+ List<ConfiguredNode> configuredNodes = idealGroup.getNodes();
+ ScoredNode node = new ScoredNode(0, 0, 0);
+ for (ConfiguredNode configuredNode : configuredNodes) {
+ NodeState nodeState = state.getNodeState(new Node(NodeType.DISTRIBUTOR, configuredNode.index()));
+ if (!nodeState.getState().oneOf(upStates)) continue;
+ if (configuredNode.index() != randomIndex) {
+ if (configuredNode.index() < randomIndex) {
+ random.setSeed(seed);
+ randomIndex = 0;
+ }
+ for (int k=randomIndex; k < configuredNode.index(); ++k) {
+ random.nextDouble();
+ }
+ randomIndex = configuredNode.index();
+ }
+ double score = random.nextDouble();
+ ++randomIndex;
+ if (Math.abs(nodeState.getCapacity() - 1.0) > 0.0000001) {
+ score = Math.pow(score, 1.0 / nodeState.getCapacity());
+ }
+ if (score > node.score) {
+ node = new ScoredNode(configuredNode.index(), 1, score);
+ }
+ }
+ if (node.reliability == 0) {
+ throw new NoDistributorsAvailableException(
+ "No available distributors in any of the given upstates '"
+ + upStates + "'.");
+ }
+ return node.index;
+ }
+ private boolean visitGroups(GroupVisitor visitor, Map<Integer, Group> groups) {
+ for (Group g : groups.values()) {
+ if (!visitor.visitGroup(g)) return false;
+ if (!g.isLeafGroup()) {
+ if (!visitGroups(visitor, g.getSubgroups())) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+ public void visitGroups(GroupVisitor visitor) {
+ Map<Integer, Group> groups = new TreeMap<>();
+ groups.put(nodeGraph.getIndex(), nodeGraph);
+ visitGroups(visitor, groups);
+ }
+ public Set<ConfiguredNode> getNodes() {
+ final Set<ConfiguredNode> nodes = new HashSet<>();
+ GroupVisitor visitor = new GroupVisitor() {
+ @Override
+ public boolean visitGroup(Group g) {
+ if (g.isLeafGroup()) {
+ nodes.addAll(g.getNodes());
+ }
+ return true;
+ }
+ };
+ visitGroups(visitor);
+ return nodes;
+ }
+
+ public static String getDefaultDistributionConfig(int redundancy, int nodeCount) {
+ return getDefaultDistributionConfig(redundancy, nodeCount, StorDistributionConfig.Disk_distribution.MODULO_BID);
+ }
+
+ public static String getDefaultDistributionConfig(int redundancy, int nodeCount, StorDistributionConfig.Disk_distribution.Enum diskDistribution) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("raw:redundancy ").append(redundancy).append("\n")
+ .append("group[1]\n")
+ .append("group[0].index \"invalid\"\n")
+ .append("group[0].name \"invalid\"\n")
+ .append("group[0].partitions \"*\"\n")
+ .append("group[0].nodes[").append(nodeCount).append("]\n");
+ for (int i=0; i<nodeCount; ++i) {
+ sb.append("group[0].nodes[").append(i).append("].index ").append(i).append("\n");
+ }
+ sb.append("disk_distribution ").append(diskDistribution.toString()).append("\n");
+ return sb.toString();
+ }
+ public static String getSimpleGroupConfig(int redundancy, int nodeCount) {
+ return getSimpleGroupConfig(redundancy, nodeCount, StorDistributionConfig.Disk_distribution.Enum.MODULO_BID);
+ }
+ public static String getSimpleGroupConfig(int redundancy, int nodeCount, StorDistributionConfig.Disk_distribution.Enum diskDistribution) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("raw:redundancy ").append(redundancy).append("\n").append("group[4]\n");
+
+ int group = 0;
+ sb.append("group[" + group + "].index \"invalid\"\n")
+ .append("group[" + group + "].name \"invalid\"\n")
+ .append("group[" + group + "].partitions \"1|*\"\n");
+
+ ++group;
+ sb.append("group[" + group + "].index \"0\"\n")
+ .append("group[" + group + "].name \"east\"\n")
+ .append("group[" + group + "].partitions \"*\"\n");
+
+ ++group;
+ sb.append("group[" + group + "].index \"0.0\"\n")
+ .append("group[" + group + "].name \"g1\"\n")
+ .append("group[" + group + "].partitions \"*\"\n")
+ .append("group[" + group + "].nodes[").append((nodeCount + 1) / 2).append("]\n");
+ for (int i=0; i<nodeCount; i += 2) {
+ sb.append("group[" + group + "].nodes[").append(i / 2).append("].index ").append(i).append("\n");
+ }
+
+ ++group;
+ sb.append("group[" + group + "].index \"0.1\"\n")
+ .append("group[" + group + "].name \"g2\"\n")
+ .append("group[" + group + "].partitions \"*\"\n")
+ .append("group[" + group + "].nodes[").append(nodeCount / 2).append("]\n");
+ for (int i=1; i<nodeCount; i += 2) {
+ sb.append("group[" + group + "].nodes[").append(i / 2).append("].index ").append(i).append("\n");
+ }
+ sb.append("disk_distribution ").append(diskDistribution.toString()).append("\n");
+ return sb.toString();
+ }
+}
+
+
diff --git a/vdslib/src/main/java/com/yahoo/vdslib/distribution/Group.java b/vdslib/src/main/java/com/yahoo/vdslib/distribution/Group.java
new file mode 100644
index 00000000000..7601dd31972
--- /dev/null
+++ b/vdslib/src/main/java/com/yahoo/vdslib/distribution/Group.java
@@ -0,0 +1,300 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vdslib.distribution;
+
+import java.util.*;
+import java.text.ParseException;
+
+/**
+ * Represent a group in the tree structure of groups in hierarchical setup of VDS nodes.
+ */
+public class Group implements Comparable<Group> {
+
+ private String name;
+ private Group parent = null;
+ private int index;
+ private int distributionHash;
+ private Distribution distribution = null;
+ private double capacity;
+ private Map<Integer, Group> subgroups;
+ private List<ConfiguredNode> nodes;
+
+ public Group(int index, String name) {
+ this.name = name;
+ this.index = index;
+ this.distributionHash = 0;
+ this.distribution = null;
+ this.capacity = 1;
+ this.nodes = new ArrayList<>();
+ this.subgroups = null;
+ }
+
+ public Group(int index, String name, Distribution d) {
+ this.name = name;
+ this.index = index;
+ this.distributionHash = 0;
+ this.distribution = d;
+ this.capacity = 1;
+ this.nodes = null;
+ this.subgroups = new TreeMap<>();
+ }
+
+ private String getPathWithSeparator(String separator) {
+ if (parent != null) {
+ final String prefix = parent.getPathWithSeparator(separator);
+ return prefix.isEmpty() ? name : prefix + separator + name;
+ } else {
+ return "";
+ }
+ }
+
+ public String getPath() {
+ return getPathWithSeparator(".");
+ }
+
+ public String getUnixStylePath() {
+ return "/" + getPathWithSeparator("/");
+ }
+
+ @Override
+ public int compareTo(Group o) {
+ return new Integer(index).compareTo(o.getIndex());
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if ( ! (o instanceof Group)) { return false; }
+ Group other = (Group) o;
+ if ( ! name.equals(other.name)
+ || index != other.index
+ || (distribution == null ^ other.distribution == null)
+ || (distribution != null && ! distribution.equals(other.distribution))
+ || Math.abs(capacity - other.capacity) > 0.0000001
+ || (subgroups == null ^ other.subgroups == null)
+ || (subgroups != null && !subgroups.equals(other.subgroups))
+ || (nodes == null ^ other.nodes == null)
+ || (nodes != null && !nodes.equals(other.nodes)))
+ {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return name.hashCode() +
+ 17 * index +
+ 23 * distribution.hashCode() +
+ 43 * subgroups.hashCode() +
+ 47 * nodes.hashCode();
+
+ }
+
+ @Override
+ public String toString() {
+ return toString("");
+ }
+
+ public String toString(String indent) {
+ StringBuffer sb = new StringBuffer();
+ sb.append("Group(name: ").append(name).append(", index: ").append(index);
+ if (distribution != null) sb.append(", distribution: ").append(distribution);
+ if (Math.abs(capacity - 1.0) > 0.0000001) sb.append(", capacity: ").append(capacity);
+ if (nodes != null) {
+ sb.append(", nodes( ");
+ for (ConfiguredNode node : nodes) {
+ sb.append(node.index()).append(' ');
+ }
+ sb.append(")");
+ }
+ if (subgroups != null) {
+ sb.append(", subgroups: ").append(subgroups.size());
+ }
+ sb.append(") {");
+ if (subgroups != null && subgroups.size() > 0) {
+ for (Group g : subgroups.values()) {
+ sb.append("\n").append(indent).append(" ");
+ sb.append(g.toString(indent + " "));
+ }
+ }
+ sb.append("\n").append(indent).append("}");
+ return sb.toString();
+ }
+
+ public void addSubGroup(Group g) {
+ if (distribution == null) {
+ throw new IllegalStateException("Cannot add sub groups to a node without distribution set.");
+ }
+ if (subgroups.containsKey(g.getIndex())) {
+ throw new IllegalStateException("A subgroup with index " + g.getIndex() + " already exist.");
+ }
+ if (nodes != null) {
+ throw new IllegalStateException("Cannot add subgroup to leaf group with nodes");
+ }
+ g.parent = this;
+ subgroups.put(g.getIndex(), g);
+ }
+
+ public void setCapacity(double c) { capacity = c; }
+
+ public void setNodes(List<ConfiguredNode> nodes) {
+ if (distribution != null) {
+ throw new IllegalStateException("Cannot add nodes to non-leaf group with distribution set");
+ }
+ if (subgroups != null) {
+ throw new IllegalStateException("Cannot add nodes to group with children");
+ }
+ this.nodes = new ArrayList<>(nodes);
+ Collections.sort(this.nodes);
+ }
+
+ public String getName() { return name; }
+ public int getIndex() { return index; }
+ public List<ConfiguredNode> getNodes() { return Collections.unmodifiableList(nodes); }
+ public Map<Integer, Group> getSubgroups() { return Collections.unmodifiableMap(subgroups); }
+ public double getCapacity() { return capacity; }
+ public int getDistributionHash() { return distributionHash; }
+ public boolean isLeafGroup() { return (distribution == null); }
+ public Distribution getDistribution() { return distribution; }
+
+ /**
+ * The distribution hashes is hopefully unique numbers for each group that is used to adjust the seed generated
+ * for groups. This is called by Distribution during configuration on the root node. It recursively generates all hashes.
+ */
+ void calculateDistributionHashValues() {
+ calculateDistributionHashValues(0x8badf00d);
+ }
+
+ private void calculateDistributionHashValues(int parentHash) {
+ distributionHash = parentHash ^ (1664525 * index + 1013904223);
+ if (subgroups == null) return;
+ for (Map.Entry<Integer, Group> entry : subgroups.entrySet()) {
+ entry.getValue().calculateDistributionHashValues(distributionHash);
+ }
+ }
+
+ public Group getGroupForNode(int index) {
+ if (nodes != null) {
+ for (ConfiguredNode node : nodes) {
+ if (node.index() == index) {
+ return this;
+ }
+ }
+ }
+
+ if (subgroups != null) {
+ for (Group group : subgroups.values()) {
+ Group retVal = group.getGroupForNode(index);
+ if (retVal != null) {
+ return retVal;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * The distribution class keeps precalculated arrays for distributions for all legal redundancies. The class is
+ * immutable, such that it can be returned safely out from the group object.
+ */
+ public static class Distribution {
+
+ private final int[] distributionSpec;
+ private final int[][] preCalculatedResults;
+
+ public Distribution(String serialized, int maxRedundancy) throws ParseException {
+ StringTokenizer st = new StringTokenizer(serialized, "|");
+ // Create the distribution spec
+ int[] distributionSpec = new int[st.countTokens()];
+ for (int i=0; i<distributionSpec.length; ++i) {
+ String token = st.nextToken();
+ try{
+ distributionSpec[i] = (token.equals("*") ? 0 : Integer.valueOf(token));
+ } catch (NumberFormatException e) {
+ throw new ParseException("Illegal distribution spec \"" + serialized + "\". Copy counts must be integer values in the range 1-255.", i);
+ }
+ if (!token.equals("*") && distributionSpec[i] == 0) {
+ throw new ParseException("Illegal distribution spec \"" + serialized + "\". Copy counts must be in the range 1-255.", i);
+ }
+ }
+ // Verify sanity of the distribution spec
+ int firstAsterix = distributionSpec.length;
+ for (int i=0; i<distributionSpec.length; ++i) {
+ if (i > firstAsterix) {
+ if (distributionSpec[i] != 0) {
+ throw new ParseException("Illegal distribution spec \"" + serialized + "\". Asterix specification must be tailing the specification.", i);
+ }
+ continue;
+ }
+ if (i < firstAsterix && distributionSpec[i] == 0) {
+ firstAsterix = i;
+ continue;
+ }
+ if (distributionSpec[i] <= 0 || distributionSpec[i] >= 256) {
+ throw new ParseException("Illegal distribution spec \"" + serialized + "\". Copy counts must be in the range 1-255.", i);
+ }
+ }
+ this.distributionSpec = distributionSpec;
+ // Create the pre calculated results
+ if (maxRedundancy <= 0 || maxRedundancy > 255) throw new IllegalArgumentException("The max redundancy must be a positive number in the range 1-255.");
+ int asterixCount = distributionSpec.length - firstAsterix;
+ int[][] preCalculations = new int[maxRedundancy + 1][];
+ for (int i=1; i<=maxRedundancy; ++i) {
+ List<Integer> spec = new ArrayList<Integer>();
+ for (int j=0; j<distributionSpec.length; ++j) {
+ spec.add(distributionSpec[j]);
+ }
+ int remainingRedundancy = i;
+ for (int j=0; j<firstAsterix; ++j) {
+ spec.set(j, Math.min(remainingRedundancy, spec.get(j)));
+ remainingRedundancy -= spec.get(j);
+ }
+ int divided = remainingRedundancy / asterixCount;
+ remainingRedundancy = remainingRedundancy % asterixCount;
+ for (int j=firstAsterix; j<spec.size(); ++j) {
+ spec.set(j, divided + (j - firstAsterix < remainingRedundancy ? 1 : 0));
+ }
+ while (spec.get(spec.size() - 1) == 0) {
+ spec.remove(spec.size() - 1);
+ }
+ preCalculations[i] = new int[spec.size()];
+ Collections.sort(spec);
+ for (int j=0; j<spec.size(); ++j) preCalculations[i][j] = spec.get(spec.size() - 1 - j);
+ }
+ this.preCalculatedResults = preCalculations;
+ }
+
+ public int[] getRedundancyArray(int redundancy) {
+ if (redundancy == 0 || redundancy >= preCalculatedResults.length) {
+ throw new IllegalArgumentException("Can only retrieve redundancy arrays in the inclusive range 1-" + (preCalculatedResults.length - 1) + ".");
+ }
+ return preCalculatedResults[redundancy];
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if ( ! (o instanceof Distribution)) return false;
+ Distribution other = (Distribution) o;
+ return (distributionSpec == other.distributionSpec && preCalculatedResults.length == other.preCalculatedResults.length);
+ }
+
+ @Override
+ public int hashCode() {
+ return Arrays.hashCode(distributionSpec) + 13 * preCalculatedResults.length;
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ for (int i=0; i<distributionSpec.length; ++i) {
+ if (i != 0) sb.append('|');
+ if (distributionSpec[i] == 0) sb.append('*');
+ else sb.append(distributionSpec[i]);
+ }
+ return sb.toString();
+ }
+ }
+
+}
diff --git a/vdslib/src/main/java/com/yahoo/vdslib/distribution/GroupVisitor.java b/vdslib/src/main/java/com/yahoo/vdslib/distribution/GroupVisitor.java
new file mode 100644
index 00000000000..493413b4e36
--- /dev/null
+++ b/vdslib/src/main/java/com/yahoo/vdslib/distribution/GroupVisitor.java
@@ -0,0 +1,8 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vdslib.distribution;
+
+public interface GroupVisitor {
+
+ public boolean visitGroup(Group g);
+
+}
diff --git a/vdslib/src/main/java/com/yahoo/vdslib/distribution/RandomGen.java b/vdslib/src/main/java/com/yahoo/vdslib/distribution/RandomGen.java
new file mode 100644
index 00000000000..9a0a1264529
--- /dev/null
+++ b/vdslib/src/main/java/com/yahoo/vdslib/distribution/RandomGen.java
@@ -0,0 +1,18 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vdslib.distribution;
+
+public class RandomGen extends java.util.Random {
+
+ public RandomGen() {
+ super();
+ }
+
+ public RandomGen(long seed) {
+ super(seed);
+ }
+
+ public void setSeed(long seed){
+ super.setSeed(seed);
+ nextDouble();
+ }
+}
diff --git a/vdslib/src/main/java/com/yahoo/vdslib/distribution/package-info.java b/vdslib/src/main/java/com/yahoo/vdslib/distribution/package-info.java
new file mode 100644
index 00000000000..c4dfd2eca11
--- /dev/null
+++ b/vdslib/src/main/java/com/yahoo/vdslib/distribution/package-info.java
@@ -0,0 +1,5 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+@ExportPackage
+package com.yahoo.vdslib.distribution;
+
+import com.yahoo.osgi.annotation.ExportPackage;
diff --git a/vdslib/src/main/java/com/yahoo/vdslib/loadtype/.gitignore b/vdslib/src/main/java/com/yahoo/vdslib/loadtype/.gitignore
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/vdslib/src/main/java/com/yahoo/vdslib/loadtype/.gitignore
diff --git a/vdslib/src/main/java/com/yahoo/vdslib/package-info.java b/vdslib/src/main/java/com/yahoo/vdslib/package-info.java
new file mode 100644
index 00000000000..7f38edb7ad1
--- /dev/null
+++ b/vdslib/src/main/java/com/yahoo/vdslib/package-info.java
@@ -0,0 +1,5 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+@ExportPackage
+package com.yahoo.vdslib;
+
+import com.yahoo.osgi.annotation.ExportPackage;
diff --git a/vdslib/src/main/java/com/yahoo/vdslib/state/ClusterState.java b/vdslib/src/main/java/com/yahoo/vdslib/state/ClusterState.java
new file mode 100644
index 00000000000..b3d572e48ae
--- /dev/null
+++ b/vdslib/src/main/java/com/yahoo/vdslib/state/ClusterState.java
@@ -0,0 +1,403 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vdslib.state;
+import com.yahoo.text.StringUtilities;
+
+import java.text.ParseException;
+import java.util.*;
+
+/**
+ * Be careful about changing this class, as it mirrors the ClusterState in C++.
+ * Please update both if you need to change anything.
+ */
+public class ClusterState implements Cloneable {
+
+ private int version = 0;
+ private State state = State.DOWN;
+ // nodeStates maps each of the non-up nodes that have an index <= the node count for its type.
+ private Map<Node, NodeState> nodeStates = new TreeMap<>();
+
+ // TODO: Change to one count for distributor and one for storage, rather than an array
+ // TODO: Rename, this is not the highest node count but the highest index
+ private ArrayList<Integer> nodeCount = new ArrayList<>(2);
+
+ private String description = "";
+ private int distributionBits = 16;
+ private boolean official = false;
+
+ public ClusterState(String serialized) throws ParseException {
+ nodeCount.add(0);
+ nodeCount.add(0);
+ deserialize(serialized);
+ }
+
+ public ClusterState clone() {
+ try{
+ ClusterState state = (ClusterState) super.clone();
+ state.nodeStates = new TreeMap<>();
+ for (Map.Entry<Node, NodeState> entry : nodeStates.entrySet()) {
+ state.nodeStates.put(entry.getKey(), entry.getValue().clone());
+ }
+ state.nodeCount = new ArrayList<>(2);
+ state.nodeCount.add(nodeCount.get(0));
+ state.nodeCount.add(nodeCount.get(1));
+ return state;
+ } catch (CloneNotSupportedException e) {
+ assert(false); // Should never happen
+ return null;
+ }
+ }
+
+ public boolean equals(Object o) {
+ if (!(o instanceof ClusterState)) { return false; }
+ ClusterState other = (ClusterState) o;
+ if (version != other.version
+ || !state.equals(other.state)
+ || distributionBits != other.distributionBits
+ || !nodeCount.equals(other.nodeCount)
+ || !nodeStates.equals(other.nodeStates))
+ {
+ return false;
+ }
+ return true;
+ }
+
+ public boolean similarTo(Object o) {
+ if (!(o instanceof ClusterState)) { return false; }
+ ClusterState other = (ClusterState) o;
+
+ if (state.equals(State.DOWN) && other.state.equals(State.DOWN)) return true; // both down, means equal (why??)
+ if (version != other.version || !state.equals(other.state)) return false;
+ if (distributionBits != other.distributionBits) return false;
+ if ( ! nodeCount.equals(other.nodeCount)) return false;
+
+ for (Map.Entry<Node, NodeState> nodeStateEntry : nodeStates.entrySet()) {
+ NodeState otherNodeState = other.nodeStates.get(nodeStateEntry.getKey());
+ if (otherNodeState == null || ! otherNodeState.similarTo(nodeStateEntry.getValue())) return false;
+ }
+ return true;
+ }
+
+ /**
+ * Fleet controller marks states that are actually sent out to nodes as official states. Only fleetcontroller
+ * should set this to official, and only just before sending it out. This state is currently not serialized with
+ * the system state, but only used internally in the fleetcontroller. Might be useful client side though, where
+ * clients modify states to mark nodes down that they cannot speak with.
+ */
+ public void setOfficial(boolean official) { this.official = official; }
+ /** Whether this system state is an unmodified version of an official system state. */
+ public boolean isOfficial() { return official; }
+
+ /** Used during deserialization */
+ private class NodeData {
+
+ boolean empty = true;
+ Node node = new Node(NodeType.STORAGE, 0);
+ StringBuilder sb = new StringBuilder();
+
+ public void addNodeState() throws ParseException {
+ if (!empty) {
+ NodeState ns = NodeState.deserialize(node.getType(), sb.toString());
+ if (!ns.equals(new NodeState(node.getType(), State.UP))) {
+ nodeStates.put(node, ns);
+ }
+ if (nodeCount.get(node.getType().ordinal()) <= node.getIndex()) {
+ nodeCount.set(node.getType().ordinal(), node.getIndex() + 1);
+ }
+ }
+ empty = true;
+ sb = new StringBuilder();
+ }
+ }
+
+ private void deserialize(String serialized) throws ParseException {
+ official = false;
+ StringTokenizer st = new StringTokenizer(serialized, " \t\n\f\r", false);
+ NodeData nodeData = new NodeData();
+ String lastAbsolutePath = "";
+ state = State.UP;
+ while (st.hasMoreTokens()) {
+ String token = st.nextToken();
+
+ int index = token.indexOf(':');
+ if (index < 0) {
+ throw new ParseException("Token " + token + " does not contain ':': " + serialized, 0);
+ }
+ String key = token.substring(0, index);
+ String value = token.substring(index + 1);
+ if (key.length() > 0 && key.charAt(0) == '.') {
+ if (lastAbsolutePath.equals("")) {
+ throw new ParseException("The first path in system state string needs to be absolute, in state: " + serialized, 0);
+ }
+ key = lastAbsolutePath + key;
+ } else {
+ lastAbsolutePath = key;
+ }
+ if (key.length() > 0) switch (key.charAt(0)) {
+ case 'c':
+ if (key.equals("cluster")) {
+ setClusterState(State.get(value));
+ continue;
+ }
+ break;
+ case 'b':
+ if (key.equals("bits")) {
+ distributionBits = Integer.parseInt(value);
+ continue;
+ }
+ break;
+ case 'v':
+ if (key.equals("version")) {
+ Integer version;
+ try{
+ version = Integer.valueOf(value);
+ } catch (Exception e) {
+ throw new ParseException("Illegal version '" + value + "'. Must be an integer, in state: " + serialized, 0);
+ }
+ setVersion(version);
+ continue;
+ }
+ break;
+ case 'm':
+ if (key.length() > 1) break;
+ setDescription(StringUtilities.unescape(value));
+ continue;
+ case 'd':
+ case 's':
+ NodeType nodeType = null;
+ int dot = key.indexOf('.');
+ String type = (dot < 0 ? key : key.substring(0, dot));
+ if (type.equals("storage")) {
+ nodeType = NodeType.STORAGE;
+ } else if (type.equals("distributor")) {
+ nodeType = NodeType.DISTRIBUTOR;
+ }
+ if (nodeType == null) break;
+ if (dot < 0) {
+ int nodeCount;
+ try{
+ nodeCount = Integer.valueOf(value);
+ } catch (Exception e) {
+ throw new ParseException("Illegal node count '" + value + "' in state: " + serialized, 0);
+ }
+ if (nodeCount > this.nodeCount.get(nodeType.ordinal())) {
+ this.nodeCount.set(nodeType.ordinal(), nodeCount);
+ }
+ continue;
+ }
+ int dot2 = key.indexOf('.', dot + 1);
+ Node node;
+ if (dot2 < 0) {
+ node = new Node(nodeType, Integer.valueOf(key.substring(dot + 1)));
+ } else {
+ node = new Node(nodeType, Integer.valueOf(key.substring(dot + 1, dot2)));
+ }
+ if (node.getIndex() >= this.nodeCount.get(nodeType.ordinal())) {
+ throw new ParseException("Cannot index " + nodeType + " node " + node.getIndex() + " of " + this.nodeCount.get(nodeType.ordinal()) + " in state: " + serialized, 0);
+ }
+ if (!nodeData.node.equals(node)) {
+ nodeData.addNodeState();
+ }
+ if (dot2 < 0) {
+ break; // No default key for nodeStates.
+ } else {
+ nodeData.sb.append(' ').append(key.substring(dot2 + 1)).append(':').append(value);
+ }
+ nodeData.node = node;
+ nodeData.empty = false;
+ continue;
+ default:
+ break;
+ }
+ // Ignore unknown nodeStates
+ }
+ nodeData.addNodeState();
+ removeLastNodesDownWithoutReason();
+ }
+
+ public String getTextualDifference(ClusterState other) {
+ return getDiff(other).toString();
+ }
+ public String getHtmlDifference(ClusterState other) {
+ return getDiff(other).toHtml();
+ }
+
+ public Diff getDiff(ClusterState other) {
+ Diff diff = new Diff();
+
+ if (version != other.version) {
+ diff.add(new Diff.Entry("version", version, other.version));
+ }
+ if (!state.equals(other.state)) {
+ diff.add(new Diff.Entry("cluster", state, other.state));
+ }
+ if (distributionBits != other.distributionBits) {
+ diff.add(new Diff.Entry("bits", distributionBits, other.distributionBits));
+ }
+ if (official != other.official) {
+ diff.add(new Diff.Entry("official", official, other.official));
+ }
+ for (NodeType type : NodeType.getTypes()) {
+ Diff typeDiff = new Diff();
+ int maxCount = Math.max(getNodeCount(type), other.getNodeCount(type));
+ for (int i = 0; i < maxCount; i++) {
+ Node n = new Node(type, i);
+ Diff d = getNodeState(n).getDiff(other.getNodeState(n));
+ if (d.differs()) {
+ typeDiff.add(new Diff.Entry(i, d));
+ }
+ }
+ if (typeDiff.differs()) {
+ diff.add(new Diff.Entry(type, typeDiff).splitLine());
+ }
+ }
+ return diff;
+ }
+
+ public int getVersion() {
+ return version;
+ }
+
+ public void setVersion(int version) {
+ official = false;
+ this.version = version;
+ }
+
+ public int getDistributionBitCount() { return distributionBits; }
+ public void setDistributionBits(int bits) { distributionBits = bits; }
+
+ /**
+ * Returns the state of this cluster state. In particular, it does not return the cluster state,
+ * no matter what the function name says.
+ */
+ public State getClusterState() { return state; }
+
+ /**
+ * Sets the state of this cluster state. In particular, it does not set the cluster state,
+ * no matter what the function name says.
+ */
+ public void setClusterState(State s) {
+ if (!s.validClusterState()) {
+ throw new IllegalArgumentException("Illegal cluster state " + s);
+ }
+ state = s;
+ }
+
+ /**
+ * Take the distributor nodes as an example. Let X be the highest index of
+ * the distributor nodes added through setNodeState(). Let Y be the number
+ * of suffix nodes for which the state is down and without description.
+ * E.g. if node X is down and without description, but nodex X-1 is up, then Y is 1.
+ * The node count for distributors is then X + 1 - Y.
+ */
+ public int getNodeCount(NodeType type) { return nodeCount.get(type.ordinal()); }
+
+ /**
+ * Returns the state of a node.
+ * If the node is not known this returns a node in the state UP (never null) if it has lower index than the max
+ * and DOWN otherwise.
+ */
+ public NodeState getNodeState(Node node) {
+ if (node.getIndex() >= nodeCount.get(node.getType().ordinal()))
+ return new NodeState(node.getType(), State.DOWN);
+ return nodeStates.getOrDefault(node, new NodeState(node.getType(), State.UP));
+ }
+
+ /**
+ * Set the node state of the given node.
+ *
+ * Automatically adjusts number of nodes of that given type if out of range of current nodes seen.
+ */
+ public void setNodeState(Node node, NodeState newState) {
+ newState.verifyValidInSystemState(node.getType());
+ if (node.getIndex() >= nodeCount.get(node.getType().ordinal())) {
+ for (int i= nodeCount.get(node.getType().ordinal()); i<node.getIndex(); ++i) {
+ nodeStates.put(new Node(node.getType(), i), new NodeState(node.getType(), State.DOWN));
+ }
+ nodeCount.set(node.getType().ordinal(), node.getIndex() + 1);
+ }
+ if (newState.equals(new NodeState(node.getType(), State.UP))) {
+ nodeStates.remove(node);
+ } else {
+ nodeStates.put(node, newState);
+ }
+ if (newState.getState().equals(State.DOWN)) {
+ // We might be setting the last node down, so we can remove some states
+ removeLastNodesDownWithoutReason();
+ }
+ }
+
+ private void removeLastNodesDownWithoutReason() {
+ for (NodeType nodeType : NodeType.values()) {
+ for (int index = nodeCount.get(nodeType.ordinal()) - 1; index >= 0; --index) {
+ Node node = new Node(nodeType, index);
+ NodeState nodeState = nodeStates.get(node);
+ if (nodeState == null) break; // Node not existing is up
+ if ( ! nodeState.getState().equals(State.DOWN)) break; // Node not down can not be removed
+ if (nodeState.hasDescription()) break; // Node have reason to be down. Don't remove node as we will forget reason
+ nodeStates.remove(node);
+ nodeCount.set(nodeType.ordinal(), node.getIndex());
+ }
+ }
+ }
+
+ public String getDescription() { return description; }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ /** Returns the serialized form of this cluster state */
+ // TODO: Don't rely on toString for that
+ @Override
+ public String toString() { return toString(false); }
+
+ public String toString(boolean verbose) {
+ StringBuilder sb = new StringBuilder();
+
+ if (version != 0) {
+ sb.append(" version:").append(version);
+ }
+
+ if (!state.equals(State.UP)) {
+ sb.append(" cluster:").append(state.serialize());
+ }
+
+ if (distributionBits != 16) {
+ sb.append(" bits:").append(distributionBits);
+ }
+
+ int distributorNodeCount = getNodeCount(NodeType.DISTRIBUTOR);
+ int storageNodeCount = getNodeCount(NodeType.STORAGE);
+ // If not printing verbose, we're not printing descriptions, so we can remove tailing nodes that are down that has descriptions too
+ if (!verbose) {
+ while (distributorNodeCount > 0 && getNodeState(new Node(NodeType.DISTRIBUTOR, distributorNodeCount - 1)).getState().equals(State.DOWN)) --distributorNodeCount;
+ while (storageNodeCount > 0 && getNodeState(new Node(NodeType.STORAGE, storageNodeCount - 1)).getState().equals(State.DOWN)) --storageNodeCount;
+ }
+ if (distributorNodeCount > 0){
+ sb.append(" distributor:").append(distributorNodeCount);
+ for (Map.Entry<Node, NodeState> entry : nodeStates.entrySet()) {
+ if (entry.getKey().getType().equals(NodeType.DISTRIBUTOR) && entry.getKey().getIndex() < distributorNodeCount) {
+ String nodeState = entry.getValue().serialize(entry.getKey().getIndex(), verbose);
+ if (!nodeState.isEmpty()) {
+ sb.append(' ').append(nodeState);
+ }
+ }
+ }
+ }
+ if (storageNodeCount > 0){
+ sb.append(" storage:").append(storageNodeCount);
+ for (Map.Entry<Node, NodeState> entry : nodeStates.entrySet()) {
+ if (entry.getKey().getType().equals(NodeType.STORAGE) && entry.getKey().getIndex() < storageNodeCount) {
+ String nodeState = entry.getValue().serialize(entry.getKey().getIndex(), verbose);
+ if (!nodeState.isEmpty()) {
+ sb.append(' ').append(nodeState);
+ }
+ }
+ }
+ }
+ if (sb.length() > 0) { // Remove first space if not empty
+ sb.deleteCharAt(0);
+ }
+ return sb.toString();
+ }
+}
diff --git a/vdslib/src/main/java/com/yahoo/vdslib/state/Diff.java b/vdslib/src/main/java/com/yahoo/vdslib/state/Diff.java
new file mode 100644
index 00000000000..084c2bbb851
--- /dev/null
+++ b/vdslib/src/main/java/com/yahoo/vdslib/state/Diff.java
@@ -0,0 +1,121 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vdslib.state;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * TODO: document this
+ */
+public class Diff {
+ public static class Entry {
+ String id;
+ // Values set for entries that contain diff themselves
+ String preContent;
+ String postContent;
+ boolean bold = false; // Print content in bold. Used if very important
+ // Values set for entries that contains subdiffs
+ Diff subDiff;
+ boolean splitLine = false; // If set, split this content on multiple lines
+
+ public Entry(Object id, Object pre, Object post) {
+ this.id = id.toString();
+ preContent = pre.toString();
+ postContent = post.toString();
+ }
+
+ public Entry(Object id, Diff subDiff) {
+ this.id = id.toString();
+ this.subDiff = subDiff;
+ }
+
+ public Entry bold() { bold = true; return this; }
+ public Entry splitLine() { splitLine = true; return this; }
+ }
+ private List<Entry> diff = new LinkedList<Entry>();
+
+ public void add(Entry e) { diff.add(e); }
+
+ public boolean differs() { return (!diff.isEmpty()); }
+
+ class PrintProperties {
+ boolean insertLineBreaks = false;
+ boolean ommitGroupForSingleEntries = true;
+ String lineBreak = "\n";
+ String entrySeparator = ", ";
+ String idValueSeparator = ": ";
+ String keyValueSeparator = " => ";
+ String singleGroupSeparator = "";
+ String groupStart = "[";
+ String groupStop = "]";
+ String indent = " ";
+ String boldStart = "";
+ String boldStop = "";
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ PrintProperties pp = new PrintProperties();
+ print(sb, "", pp, false);
+ return sb.toString();
+ }
+ public String toHtml() {
+ StringBuilder sb = new StringBuilder();
+ PrintProperties pp = new PrintProperties();
+ pp.lineBreak = "<br>\n";
+ pp.indent = "&nbsp;";
+ pp.keyValueSeparator = " =&gt; ";
+ pp.insertLineBreaks = true;
+ pp.boldStart = "<b>";
+ pp.boldStop = "</b>";
+ print(sb, "", pp, false);
+ return sb.toString();
+ }
+
+ public void print(StringBuilder sb, String indent, PrintProperties pp, boolean splitLines) {
+ boolean first = true;
+ for (Entry e : diff) {
+ if (first) {
+ first = false;
+ } else {
+ sb.append(pp.entrySeparator);
+ if (splitLines && pp.insertLineBreaks) {
+ sb.append(pp.lineBreak).append(indent);
+ }
+ }
+ sb.append(e.id);
+ if (e.subDiff != null) {
+ sb.append(pp.idValueSeparator);
+ if (e.subDiff.diff.size() > 1 || !pp.ommitGroupForSingleEntries) {
+ sb.append(pp.groupStart);
+ } else {
+ sb.append(pp.singleGroupSeparator);
+ }
+ if (e.splitLine && pp.insertLineBreaks) {
+ sb.append(pp.lineBreak).append(indent + pp.indent);
+ }
+ e.subDiff.print(sb, indent + pp.indent, pp, e.splitLine);
+ if (e.splitLine && pp.insertLineBreaks) {
+ sb.append(pp.lineBreak).append(indent);
+ }
+ if (e.subDiff.diff.size() > 1 || !pp.ommitGroupForSingleEntries) {
+ sb.append(pp.groupStop);
+ }
+ } else {
+ if (!e.id.isEmpty()) {
+ sb.append(pp.idValueSeparator);
+ }
+ if (e.bold) {
+ sb.append(pp.boldStart).append(e.preContent).append(pp.boldStop)
+ .append(pp.keyValueSeparator)
+ .append(pp.boldStart).append(e.postContent).append(pp.boldStop);
+ } else {
+ sb.append(e.preContent)
+ .append(pp.keyValueSeparator)
+ .append(e.postContent);
+ }
+ }
+ }
+ }
+
+}
diff --git a/vdslib/src/main/java/com/yahoo/vdslib/state/DiskState.java b/vdslib/src/main/java/com/yahoo/vdslib/state/DiskState.java
new file mode 100644
index 00000000000..fb91af14f90
--- /dev/null
+++ b/vdslib/src/main/java/com/yahoo/vdslib/state/DiskState.java
@@ -0,0 +1,128 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vdslib.state;
+
+import com.yahoo.text.StringUtilities;
+
+import java.util.StringTokenizer;
+import java.text.ParseException;
+
+/**
+ *
+ */
+public class DiskState implements Cloneable {
+ private State state = State.UP;
+ private String description = "";
+ private double capacity = 1.0;
+
+ public DiskState() {}
+ public DiskState(State s) {
+ setState(s);
+ }
+ public DiskState(State s, String description, double capacity) {
+ setState(s); // Set via set methods, so we can have illegal argument checks only one place
+ setCapacity(capacity);
+ setDescription(description);
+ }
+ public DiskState clone() {
+ try{
+ return (DiskState) super.clone();
+ } catch (CloneNotSupportedException e) {
+ assert(false); // Should not happen
+ return null;
+ }
+ }
+
+ public DiskState(String serialized) throws ParseException {
+ StringTokenizer st = new StringTokenizer(serialized, " \t\f\r\n");
+ while (st.hasMoreTokens()) {
+ String token = st.nextToken();
+ int index = token.indexOf(':');
+ if (index < 0) {
+ throw new ParseException("Token " + token + " does not contain ':': " + serialized, 0);
+ }
+ String key = token.substring(0, index);
+ String value = token.substring(index + 1);
+ if (key.length() > 0) switch (key.charAt(0)) {
+ case 's':
+ if (key.length() > 1) break;
+ setState(State.get(value));
+ continue;
+ case 'c':
+ if (key.length() > 1) break;
+ try{
+ setCapacity(Double.valueOf(value));
+ } catch (Exception e) {
+ throw new ParseException("Illegal disk capacity '" + value + "'. Capacity must be a positive floating point number", 0);
+ }
+ continue;
+ case 'm':
+ if (key.length() > 1) break;
+ description = StringUtilities.unescape(value);
+ continue;
+ default:
+ break;
+ }
+ // Ignore unknown tokens
+ }
+ }
+
+ public String serialize(String prefix, boolean includeDescription) {
+ boolean empty = true;
+ StringBuilder sb = new StringBuilder();
+ if (!state.equals(State.UP) || prefix.length() < 2) {
+ sb.append(prefix).append("s:").append(state.serialize());
+ empty = false;
+ }
+ if (Math.abs(capacity - 1.0) > 0.000000001) {
+ if (empty) { empty = false; } else { sb.append(' '); }
+ sb.append(prefix).append("c:").append(capacity);
+ }
+ if (includeDescription && description.length() > 0) {
+ if (!empty) { sb.append(' '); }
+ sb.append(prefix).append("m:").append(StringUtilities.escape(description, ' '));
+ }
+ return sb.toString();
+ }
+
+ public State getState() { return state; }
+ public double getCapacity() { return capacity; }
+ public String getDescription() { return description; }
+
+ public void setState(State s) {
+ if (!s.validDiskState()) {
+ throw new IllegalArgumentException("State " + s + " is not a valid disk state.");
+ }
+ state = s;
+ }
+ public void setCapacity(double capacity) {
+ if (capacity < 0) {
+ throw new IllegalArgumentException("Negative capacity makes no sense.");
+ }
+ this.capacity = capacity;
+ }
+ public void setDescription(String desc) { description = desc; }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("DiskState(").append(state.serialize());
+ if (Math.abs(capacity - 1.0) > 0.00000001) {
+ sb.append(", capacity ").append(capacity);
+ }
+ if (description.length() > 0) {
+ sb.append(": ").append(description);
+ }
+ sb.append(")");
+ return sb.toString();
+ }
+
+ public boolean equals(Object o) {
+ if (!(o instanceof DiskState)) { return false; }
+ DiskState other = (DiskState) o;
+ if (state.equals(other.state)
+ && Math.abs(capacity - other.capacity) < 0.00000001)
+ {
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/vdslib/src/main/java/com/yahoo/vdslib/state/Node.java b/vdslib/src/main/java/com/yahoo/vdslib/state/Node.java
new file mode 100644
index 00000000000..832120d6b5b
--- /dev/null
+++ b/vdslib/src/main/java/com/yahoo/vdslib/state/Node.java
@@ -0,0 +1,52 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vdslib.state;
+
+/**
+ * A node in a content cluster. This is immutable.
+ */
+public class Node implements Comparable<Node> {
+
+ private final NodeType type;
+ private final int index;
+
+ public Node(NodeType type, int index) {
+ this.type = type;
+ this.index = index;
+ }
+
+ public Node(String serialized) {
+ int dot = serialized.lastIndexOf('.');
+ if (dot < 0) throw new IllegalArgumentException("Not a legal node string '" + serialized + "'.");
+ type = NodeType.get(serialized.substring(0, dot));
+ index = Integer.valueOf(serialized.substring(dot + 1));
+ }
+
+ public String toString() {
+ return type.toString() + "." + index;
+ }
+
+ public NodeType getType() { return type; }
+ public int getIndex() { return index; }
+
+ private int getOrdering() {
+ return (type.equals(NodeType.STORAGE) ? 65536 : 0) + index;
+ }
+
+ @Override
+ public int compareTo(Node n) {
+ return getOrdering() - n.getOrdering();
+ }
+
+ @Override
+ public int hashCode() {
+ return type.hashCode() ^ index;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof Node)) return false;
+ Node n = (Node) o;
+ return (type.equals(n.type) && index == n.index);
+ }
+
+}
diff --git a/vdslib/src/main/java/com/yahoo/vdslib/state/NodeState.java b/vdslib/src/main/java/com/yahoo/vdslib/state/NodeState.java
new file mode 100644
index 00000000000..8c31938dfaf
--- /dev/null
+++ b/vdslib/src/main/java/com/yahoo/vdslib/state/NodeState.java
@@ -0,0 +1,499 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vdslib.state;
+
+import com.yahoo.text.StringUtilities;
+
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+import java.util.StringTokenizer;
+
+/**
+ * The state of a single node in the cluster state
+ * TODO: The config aspects of this should move to ConfiguredNode
+ * TODO: The type should be removed, as it is part of the owner.
+ * TODO: Monitoring aspects should move to NodeInfo
+ */
+public class NodeState implements Cloneable {
+
+ private final NodeType type;
+ private State state = State.UP;
+ private String description = "";
+ private double capacity = 1.0;
+ private int reliability = 1;
+ private double initProgress = 1.0;
+ private int minUsedBits = 16;
+ private List<DiskState> diskStates = new ArrayList<>();
+ /** When generating ideal states, we want to cheaply check if any disks are down in the nodestate. */
+ private boolean anyDiskDown = false;
+ private long startTimestamp = 0;
+
+ public static double getListingBucketsInitProgressLimit() { return 0.01; }
+
+ public NodeState(NodeType type, State state) {
+ this.type = type;
+ this.state = state;
+ updateAnyDiskDownFlag();
+ }
+
+ private void updateAnyDiskDownFlag() {
+ boolean anyDown = false;
+ for (DiskState ds : diskStates) {
+ if (!ds.getState().equals(State.UP)) {
+ anyDown = true;
+ break;
+ }
+ }
+ anyDiskDown = anyDown;
+ }
+
+ public NodeState clone() {
+ try{
+ NodeState ns = (NodeState) super.clone();
+ ns.diskStates = new ArrayList<>();
+ for (DiskState s : diskStates) {
+ ns.diskStates.add(s.clone());
+ }
+ return ns;
+ } catch (CloneNotSupportedException e) {
+ throw new RuntimeException("Does not happen");
+ }
+ }
+
+ /**
+ * A state can not be forced to be in a state above it's reported state.
+ * For instance, a down being down, cannot be forced up, but a node being down can be forced in maintenance.
+ */
+ public boolean above(NodeState other) {
+ return (state.ordinal() > other.state.ordinal());
+ }
+
+ public boolean equals(Object o) {
+ if (!(o instanceof NodeState)) { return false; }
+ NodeState ns = (NodeState) o;
+ if (state != ns.state
+ || Math.abs(capacity - ns.capacity) > 0.0000000001
+ || Math.abs(reliability - ns.reliability) > 0.0000000001
+ || Math.abs(initProgress - ns.initProgress) > 0.0000000001
+ || startTimestamp != ns.startTimestamp
+ || minUsedBits != ns.minUsedBits)
+ {
+ return false;
+ }
+ if (diskStates.size() == 0 && ns.diskStates.size() == 0) {
+ // Everything is fine
+ } else if (diskStates.size() == 0 || ns.diskStates.size() == 0) {
+ NodeState nonEmptyState = (diskStates.size() == 0 ? ns : this);
+ for (int i=0; i<nonEmptyState.diskStates.size(); ++i) {
+ if (!nonEmptyState.diskStates.get(i).equals(new DiskState(State.UP))) {
+ return false;
+ }
+ }
+ } else if (diskStates.size() != ns.diskStates.size()) {
+ return false;
+ } else {
+ for (int i=0; i<diskStates.size(); ++i) {
+ if (!diskStates.get(i).equals(ns.diskStates.get(i))) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+ public int hashCode() {
+ return state.hashCode() ^ diskStates.hashCode() ^ new Double(capacity).hashCode() ^ new Double(reliability).hashCode();
+ }
+
+ /**
+ * States are similar if the cluster state doesn't need to be updated due to a change.
+ * Note that min dist bits may need to alter cluster state, but as we don't know at this point, we ignore it.
+ * Cluster state will check for that.
+ */
+ public boolean similarTo(Object o) {
+ if (!(o instanceof NodeState)) { return false; }
+ NodeState other = (NodeState) o;
+
+ if (state != other.state) return false;
+ if (Math.abs(capacity - other.capacity) > 0.0000000001) return false;
+ if (Math.abs(reliability - other.reliability) > 0.0000000001) return false;
+ if (startTimestamp != other.startTimestamp) return false;
+
+ // Init progress on different sides of the init progress limit boundary is not similar.
+ if (type.equals(NodeType.STORAGE)
+ && initProgress < getListingBucketsInitProgressLimit() ^ other.initProgress < getListingBucketsInitProgressLimit())
+ {
+ return false;
+ }
+
+ if (diskStates.size() == 0 && other.diskStates.size() == 0) {
+ // Everything is fine
+ } else if (diskStates.size() == 0 || other.diskStates.size() == 0) {
+ NodeState nonEmptyState = (diskStates.size() == 0 ? other : this);
+ for (int i=0; i<nonEmptyState.diskStates.size(); ++i) {
+ if (!nonEmptyState.diskStates.get(i).equals(new DiskState(State.UP))) {
+ return false;
+ }
+ }
+ } else if (diskStates.size() != other.diskStates.size()) {
+ return false;
+ } else {
+ for (int i=0; i<diskStates.size(); ++i) {
+ if (!diskStates.get(i).equals(other.diskStates.get(i))) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ public Diff getDiff(NodeState other) {
+ Diff diff = new Diff();
+ if (!state.equals(other.state)) {
+ diff.add(new Diff.Entry("", state, other.state).bold());
+ }
+ if (Math.abs(capacity - other.capacity) > 0.000000001) {
+ diff.add(new Diff.Entry("capacity", capacity, other.capacity));
+ }
+ if (Math.abs(reliability - other.reliability) > 0.000000001) {
+ diff.add(new Diff.Entry("reliability", reliability, other.reliability));
+ }
+ if (minUsedBits != other.minUsedBits) {
+ diff.add(new Diff.Entry("minUsedBits", minUsedBits, other.minUsedBits));
+ }
+ if (Math.abs(initProgress - other.initProgress) > 0.000000001 && state.equals(State.INITIALIZING) && other.state.equals(State.INITIALIZING)) {
+ diff.add(new Diff.Entry("initProgress", initProgress, other.initProgress));
+ }
+ if (startTimestamp != other.startTimestamp) {
+ diff.add(new Diff.Entry("startTimestamp", startTimestamp, other.startTimestamp));
+ }
+ if (diskStates.size() != other.diskStates.size()) {
+ diff.add(new Diff.Entry("disks", diskStates.size(), other.diskStates.size()));
+ } else {
+ Diff diskDiff = new Diff();
+ for (int i=0; i<diskStates.size(); ++i) {
+ if (!diskStates.get(i).equals(other.diskStates.get(i))) {
+ diskDiff.add(new Diff.Entry(i, diskStates.get(i), other.diskStates.get(i)));
+ }
+ }
+ if (diskDiff.differs()) {
+ diff.add(new Diff.Entry("disks", diskDiff));
+ }
+ }
+ if (!description.equals(other.description)) {
+ diff.add(new Diff.Entry("description", description, other.description));
+ }
+ return diff;
+ }
+
+ public String getTextualDifference(NodeState other) {
+ return getDiff(other).toString();
+ }
+
+ /** Capacity is set by deserializing a node state. This seems odd, as it is config */
+ public NodeState setCapacity(double c) { this.capacity = c; return this; }
+
+ public NodeState setReliability(int r) { this.reliability = r; return this; }
+ public NodeState setInitProgress(double p) { this.initProgress = p; return this; }
+ public NodeState setDescription(String desc) { this.description = desc; return this; }
+ public NodeState setMinUsedBits(int u) { this.minUsedBits = u; return this; }
+ public NodeState setState(State state) { this.state = state; return this; }
+ public NodeState setStartTimestamp(long ts) { this.startTimestamp = ts; return this; }
+
+ public double getCapacity() { return this.capacity; }
+ public int getReliability() { return this.reliability; }
+ public double getInitProgress() { return this.initProgress; }
+ public boolean hasDescription() { return (description.length() > 0); }
+ public String getDescription() { return description; }
+ public State getState() { return this.state; }
+ public int getMinUsedBits() { return minUsedBits; }
+ public long getStartTimestamp() { return startTimestamp; }
+
+ public boolean isAnyDiskDown() { return anyDiskDown; }
+ public int getDiskCount() { return diskStates.size(); }
+ public List<DiskState> getDiskStates() { return Collections.unmodifiableList(diskStates); }
+
+ public String toString() { return toString(false); }
+
+ public String toString(boolean compact) {
+ StringBuilder sb = new StringBuilder();
+ if (compact) {
+ sb.append(state.serialize().toUpperCase());
+ } else {
+ sb.append(state);
+ }
+ if (Math.abs(capacity - 1.0) > 0.000000001) {
+ sb.append(compact ? ", c " : ", capacity ").append(compact ? String.format(Locale.ENGLISH, "%.3g", capacity) : capacity);
+ }
+ if (Math.abs(reliability - 1.0) > 0.000000001) {
+ sb.append(compact ? ", r " : ", reliability ").append(reliability);
+ }
+ if (state.equals(State.INITIALIZING)) {
+ sb.append(compact ? ", i " : ", init progress ").append(compact ? String.format(Locale.ENGLISH, "%.3g", initProgress) : initProgress);
+ if (type.equals(NodeType.STORAGE)) {
+ if (initProgress < getListingBucketsInitProgressLimit()) {
+ sb.append(compact ? " (ls)" : " (listing files)");
+ } else {
+ sb.append(compact ? " (read)" : " (reading file headers)");
+ }
+ }
+ }
+ if (startTimestamp > 0) {
+ sb.append(compact ? ", t " : ", start timestamp ").append(startTimestamp);
+ }
+ if (minUsedBits != 16) {
+ sb.append(compact ? ", b " : ", minimum used bits ").append(minUsedBits);
+ }
+
+ if (diskStates.size() > 0) {
+ if (compact) {
+ boolean anyNonDefault = false;
+ for (DiskState diskState : diskStates) {
+ anyNonDefault |= (!diskState.equals(new DiskState(State.UP)));
+ }
+ if (anyNonDefault) {
+ sb.append(",");
+ DiskState defaultDiskState = new DiskState(State.UP);
+ for (int i=0; i<diskStates.size(); ++i) {
+ if (!diskStates.get(i).equals(defaultDiskState)) {
+ sb.append(" d").append(i).append("(").append(diskStates.get(i).serialize("", false)).append(")");
+ }
+ }
+ }
+ } else {
+ sb.append(", disk states:");
+ for (int i=0; i<diskStates.size(); ++i) {
+ sb.append(" disk ").append(i).append(": ").append(diskStates.get(i).toString());
+ }
+ }
+ }
+ if (description.length() > 0) {
+ sb.append(": ").append(description);
+ }
+ return sb.toString();
+ }
+
+ public NodeState setDiskCount(int count) {
+ if (count < 0) {
+ throw new IllegalArgumentException("Count must be positive. Was "+count+".");
+ }
+ diskStates.clear();
+ for(int i=0;i<count;i++) {
+ diskStates.add(new DiskState(State.UP, "", 1.0));
+ }
+ return this;
+ }
+
+ public NodeState setDiskState(int disk, DiskState state) throws IndexOutOfBoundsException {
+ diskStates.set(disk, state);
+ updateAnyDiskDownFlag();
+ return this;
+ }
+
+ public DiskState getDiskState(int disk) throws IndexOutOfBoundsException {
+ if (diskStates.isEmpty()) { // Zero disks, means unknown amount of disks, but all are up,
+ return new DiskState(); // in which case we don't need to know amount of disks.
+ }
+ return diskStates.get(disk);
+ }
+
+ public String serialize() { return serialize(-1, false); }
+ public String serialize(boolean verbose) { return serialize(-1, verbose); }
+ public String serialize(int nodeIdx, boolean verbose) {
+ boolean empty = true;
+ StringBuilder sb = new StringBuilder();
+ String prefix = (nodeIdx == -1 ? "" : "." + nodeIdx + ".");
+ if (state != State.UP){
+ empty = false;
+ sb.append(prefix).append("s:").append(state.serialize());
+ }
+ if (Math.abs(capacity - 1.0) > 0.000000001) {
+ if (empty) { empty = false; } else { sb.append(' '); }
+ sb.append(prefix).append("c:").append(capacity);
+ }
+ if (Math.abs(reliability - 1.0) > 0.000000001) {
+ if (empty) { empty = false; } else { sb.append(' '); }
+ sb.append(prefix).append("r:").append(reliability);
+ }
+ if (state == State.INITIALIZING) {
+ sb.append(' ');
+ sb.append(prefix).append("i:").append(initProgress);
+ }
+ if (startTimestamp != 0) {
+ if (empty) { empty = false; } else { sb.append(' '); }
+ sb.append(prefix).append("t:").append(startTimestamp);
+ }
+ if (nodeIdx == -1 && minUsedBits != 16) {
+ if (empty) { empty = false; } else { sb.append(' '); }
+ sb.append(prefix).append("b:").append(minUsedBits);
+ }
+
+ if (diskStates.size() > 0) {
+ StringBuilder diskInfo = new StringBuilder();
+ for(int i = 0; i < diskStates.size(); ++i) {
+ String diskPrefix = prefix + "d." + i + ".";
+ String disk = diskStates.get(i).serialize(diskPrefix, verbose);
+ if (disk.length() > 0) {
+ diskInfo.append(' ').append(disk);
+ }
+ }
+ String diskInfoStr = diskInfo.toString();
+ if (verbose || diskInfoStr.length() > 0) {
+ if (empty) { empty = false; } else { sb.append(' '); }
+ sb.append(prefix).append("d:").append(diskStates.size());
+ sb.append(diskInfoStr);
+ } else if (nodeIdx == -1) {
+ if (empty) { empty = false; } else { sb.append(' '); }
+ sb.append(prefix).append("d:").append(diskStates.size());
+ }
+ }
+ if ((verbose || nodeIdx == -1) && description.length() > 0) {
+ if (!empty) { sb.append(' '); }
+ sb.append(prefix).append("m:").append(StringUtilities.escape(description, ' '));
+ }
+ return sb.toString();
+ }
+
+ private static class DiskData {
+
+ boolean empty = true;
+ int diskIndex = 0;
+ StringBuilder sb = new StringBuilder();
+
+ public void addDisk(NodeState ns) throws ParseException {
+ if (!empty) {
+ while (diskIndex >= ns.diskStates.size()) {
+ ns.diskStates.add(new DiskState());
+ }
+ ns.diskStates.set(diskIndex, new DiskState(sb.toString()));
+ empty = true;
+ sb = new StringBuilder();
+ }
+ }
+ }
+
+ /** Creates an instance from the serialized form produced by serialize */
+ public static NodeState deserialize(NodeType type, String serialized) throws ParseException {
+ NodeState newState = new NodeState(type, State.UP);
+ StringTokenizer st = new StringTokenizer(serialized, " \t\r\f\n", false);
+ DiskData diskData = new DiskData();
+ while (st.hasMoreTokens()) {
+ String token = st.nextToken();
+ int index = token.indexOf(':');
+ if (index < 0) {
+ throw new ParseException("Token " + token + " does not contain ':': " + serialized, 0);
+ }
+ String key = token.substring(0, index);
+ String value = token.substring(index + 1);
+ if (key.length() > 0) switch (key.charAt(0)) {
+ case 's':
+ if (key.length() > 1) break;
+ newState.setState(State.get(value));
+ continue;
+ case 'b':
+ if (key.length() > 1) break;
+ newState.setMinUsedBits(Integer.parseInt(value));
+ continue;
+ case 'c':
+ if (key.length() > 1) break;
+ if (type != null && !type.equals(NodeType.STORAGE)) break;
+ try{
+ newState.setCapacity(Double.valueOf(value));
+ } catch (Exception e) {
+ throw new ParseException("Illegal capacity '" + value + "'. Capacity must be a positive floating point number", 0);
+ }
+ continue;
+ case 'r':
+ if (key.length() > 1) break;
+ if (type != null && !type.equals(NodeType.STORAGE)) break;
+ try{
+ newState.setReliability(Integer.valueOf(value));
+ } catch (Exception e) {
+ throw new ParseException("Illegal reliability '" + value + "'. Reliability must be a positive integer number", 0);
+ }
+ continue;
+ case 'i':
+ if (key.length() > 1) break;
+ try{
+ newState.setInitProgress(Double.valueOf(value));
+ } catch (Exception e) {
+ throw new ParseException("Illegal init progress '" + value + "'. Init progress must be a floating point number from 0.0 to 1.0", 0);
+ }
+ continue;
+ case 't':
+ if (key.length() > 1) break;
+ try{
+ newState.setStartTimestamp(Long.valueOf(value));
+ if (newState.getStartTimestamp() < 0) throw new Exception();
+ } catch (Exception e) {
+ throw new ParseException("Illegal start timestamp " + value + ". Start timestamp must be 0 or a positive long.", 0);
+ }
+ continue;
+ case 'm':
+ if (key.length() > 1) break;
+ newState.setDescription(StringUtilities.unescape(value));
+ continue;
+ case 'd':
+ if (type != null && !type.equals(NodeType.STORAGE)) break;
+ if (key.length() == 1) {
+ int size;
+ try{
+ size = Integer.valueOf(value);
+ } catch (Exception e) {
+ throw new ParseException("Invalid disk count '" + value + "'. Need a positive integer value", 0);
+ }
+ while (newState.diskStates.size() < size) {
+ newState.diskStates.add(new DiskState());
+ }
+ continue;
+ }
+ if (key.charAt(1) != '.') break;
+ int diskIndex;
+ int endp = key.indexOf('.', 2);
+ String indexStr = (endp < 0 ? key.substring(2) : key.substring(2, endp));
+ try{
+ diskIndex = Integer.valueOf(indexStr);
+ } catch (Exception e) {
+ throw new ParseException("Invalid disk index '" + indexStr + "'. need a positive integer value", 0);
+ }
+ if (diskIndex >= newState.diskStates.size()) {
+ throw new ParseException("Cannot index disk " + diskIndex + " of " + newState.diskStates.size(), 0);
+ }
+ if (diskData.diskIndex != diskIndex) {
+ diskData.addDisk(newState);
+ }
+ if (endp < 0) {
+ diskData.sb.append(" s:").append(value);
+ } else {
+ diskData.sb.append(" ").append(key.substring(endp + 1)).append(':').append(value);
+ }
+ diskData.diskIndex = diskIndex;
+ diskData.empty = false;
+ continue;
+ default:
+ break;
+ }
+ // Ignore unknown tokens
+ }
+ diskData.addDisk(newState);
+ newState.updateAnyDiskDownFlag();
+ return newState;
+ }
+
+ public void verifyValidInSystemState(NodeType type) {
+ if (!state.validCurrentNodeState(type)) {
+ throw new IllegalArgumentException("State " + state + " cannot fit in system state for node of type: " + type);
+ }
+ if (type.equals(NodeType.DISTRIBUTOR) && Math.abs(capacity - 1.0) > 0.000000001) {
+ throw new IllegalArgumentException("Capacity should not be set for a distributor node");
+ }
+ if (type.equals(NodeType.DISTRIBUTOR) && Math.abs(reliability - 1.0) > 0.000000001) {
+ throw new IllegalArgumentException("Reliability should not be set for a distributor node");
+ }
+ if (type.equals(NodeType.DISTRIBUTOR) && !diskStates.isEmpty()) {
+ throw new IllegalArgumentException("Disk states should not be set for a distributor node");
+ }
+ }
+
+}
diff --git a/vdslib/src/main/java/com/yahoo/vdslib/state/NodeType.java b/vdslib/src/main/java/com/yahoo/vdslib/state/NodeType.java
new file mode 100644
index 00000000000..2c1db1c5cc2
--- /dev/null
+++ b/vdslib/src/main/java/com/yahoo/vdslib/state/NodeType.java
@@ -0,0 +1,32 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vdslib.state;
+
+public enum NodeType {
+ STORAGE("storage"),
+ DISTRIBUTOR("distributor");
+
+ private final String serializeAs;
+
+ private NodeType(String serializeAs) {
+ this.serializeAs = serializeAs;
+ }
+
+ public String toString() {
+ return serializeAs;
+ }
+
+ public static NodeType get(String serialized) {
+ for(NodeType type : values()) {
+ if (type.serializeAs.equals(serialized)) return type;
+ }
+ throw new IllegalArgumentException("Unknown node type '" + serialized + "'. Legal values are 'storage' and 'distributor'.");
+ }
+
+ public static NodeType[] getTypes() {
+ NodeType types[] = new NodeType[2];
+ types[0] = STORAGE;
+ types[1] = DISTRIBUTOR;
+ return types;
+ }
+
+}
diff --git a/vdslib/src/main/java/com/yahoo/vdslib/state/State.java b/vdslib/src/main/java/com/yahoo/vdslib/state/State.java
new file mode 100644
index 00000000000..99323dbc4de
--- /dev/null
+++ b/vdslib/src/main/java/com/yahoo/vdslib/state/State.java
@@ -0,0 +1,82 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vdslib.state;
+
+import java.util.ArrayList;
+
+/**
+ *
+ * Defines legal states for various uses. Split this into its own class such
+ * that we can easily see what states are legal to use in what situations.
+ * They double as disk states and node states nodes report they are in, and
+ * wanted states set external sources.
+ */
+public enum State {
+
+ // The order declares the ordinals, and defines what states are above/below others
+ UNKNOWN ("-", false, true, true, false, false, false, false, false), // This state is used by the fleetcontroller to indicate
+ // that we have failed to contact the node. It should never be
+ // sent out of the fleetcontroller
+ MAINTENANCE ("m", false, false, false, true, true, false, true, true),
+ DOWN ("d", true, true, true, true, true, true, true, true), // Down is not valid reported state sent from the node itself.
+ STOPPING ("s", false, true, true, false, false, true, true, true),
+ INITIALIZING("i", false, true, true, false, false, true, true, true),
+ RETIRED ("r", false, false, false, false, true, false, true, true),
+ UP ("u", true, true, true, true, true, true, true, true);
+
+ private final boolean validDiskState;
+ private final boolean validClusterState;
+ private final ArrayList<Boolean> validReportedNodeState = new ArrayList<>();
+ private final ArrayList<Boolean> validWantedNodeState = new ArrayList<>();
+ private final ArrayList<Boolean> validCurrentNodeState = new ArrayList<>();
+ private final String serializedAs;
+
+ private State(String serialized, boolean validDisk, boolean validDistReported, boolean validStorReported,
+ boolean validDistWanted, boolean validStorWanted, boolean validCluster, boolean validDistCurrent,
+ boolean validStorCurrent)
+ {
+ validDiskState = validDisk;
+ validClusterState = validCluster;
+ assert(NodeType.STORAGE.ordinal() == 0);
+ assert(NodeType.DISTRIBUTOR.ordinal() == 1);
+ validReportedNodeState.add(validStorReported);
+ validReportedNodeState.add(validDistReported);
+ validWantedNodeState.add(validStorWanted);
+ validWantedNodeState.add(validDistWanted);
+ validCurrentNodeState.add(validStorCurrent);
+ validCurrentNodeState.add(validDistCurrent);
+ this.serializedAs = serialized;
+ }
+
+ public static State get(String serialized) {
+ for (State s : values()) {
+ if (s.serializedAs.equals(serialized)) { return s; }
+ }
+ throw new IllegalArgumentException("Invalid state '" + serialized + "'.");
+ }
+
+ public String serialize() { return serializedAs; }
+
+ public boolean validDiskState() { return validDiskState; }
+ public boolean validClusterState() { return validClusterState; }
+ public boolean validReportedNodeState(NodeType type) { return validReportedNodeState.get(type.ordinal()); }
+ public boolean validWantedNodeState(NodeType type) { return validWantedNodeState.get(type.ordinal()); }
+ public boolean validCurrentNodeState(NodeType type) { return validCurrentNodeState.get(type.ordinal()); }
+
+ public boolean maySetWantedStateForThisNodeState(State s) { return (s.ordinal() <= ordinal()); }
+
+ public boolean oneOf(String states) {
+ for (char c : states.toCharArray()) {
+ String s = "" + c;
+ if (s.equals(serializedAs)) return true;
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ String id = name();
+ String lower = id.substring(1).toLowerCase();
+ return id.charAt(0) + lower;
+ }
+
+}
diff --git a/vdslib/src/main/java/com/yahoo/vdslib/state/package-info.java b/vdslib/src/main/java/com/yahoo/vdslib/state/package-info.java
new file mode 100644
index 00000000000..78662d368f2
--- /dev/null
+++ b/vdslib/src/main/java/com/yahoo/vdslib/state/package-info.java
@@ -0,0 +1,5 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+@ExportPackage
+package com.yahoo.vdslib.state;
+
+import com.yahoo.osgi.annotation.ExportPackage;
diff --git a/vdslib/src/test/files/documentlist-java.dat b/vdslib/src/test/files/documentlist-java.dat
new file mode 100644
index 00000000000..f4a097f9595
--- /dev/null
+++ b/vdslib/src/test/files/documentlist-java.dat
Binary files differ
diff --git a/vdslib/src/test/files/documentmanager.cfg b/vdslib/src/test/files/documentmanager.cfg
new file mode 100644
index 00000000000..cab4d3bfef1
--- /dev/null
+++ b/vdslib/src/test/files/documentmanager.cfg
@@ -0,0 +1,91 @@
+enablecompression false
+datatype[3]
+datatype[0].id -1007405344
+datatype[0].arraytype[0]
+datatype[0].weightedsettype[0]
+datatype[0].structtype[1]
+datatype[0].structtype[0].name benchmark.header
+datatype[0].structtype[0].version 0
+datatype[0].structtype[0].field[15]
+datatype[0].structtype[0].field[0].name seed
+datatype[0].structtype[0].field[0].id[0]
+datatype[0].structtype[0].field[0].datatype 0
+datatype[0].structtype[0].field[1].name totaldoccount
+datatype[0].structtype[0].field[1].id[0]
+datatype[0].structtype[0].field[1].datatype 0
+datatype[0].structtype[0].field[2].name totalusercount
+datatype[0].structtype[0].field[2].id[0]
+datatype[0].structtype[0].field[2].datatype 0
+datatype[0].structtype[0].field[3].name minheaderdocsize
+datatype[0].structtype[0].field[3].id[0]
+datatype[0].structtype[0].field[3].datatype 0
+datatype[0].structtype[0].field[4].name maxheaderdocsize
+datatype[0].structtype[0].field[4].id[0]
+datatype[0].structtype[0].field[4].datatype 0
+datatype[0].structtype[0].field[5].name minbodydocsize
+datatype[0].structtype[0].field[5].id[0]
+datatype[0].structtype[0].field[5].datatype 0
+datatype[0].structtype[0].field[6].name maxbodydocsize
+datatype[0].structtype[0].field[6].id[0]
+datatype[0].structtype[0].field[6].datatype 0
+datatype[0].structtype[0].field[7].name simplecontent
+datatype[0].structtype[0].field[7].id[0]
+datatype[0].structtype[0].field[7].datatype 16
+datatype[0].structtype[0].field[8].name pregeneratedcontent
+datatype[0].structtype[0].field[8].id[0]
+datatype[0].structtype[0].field[8].datatype 16
+datatype[0].structtype[0].field[9].name headerint
+datatype[0].structtype[0].field[9].id[0]
+datatype[0].structtype[0].field[9].datatype 0
+datatype[0].structtype[0].field[10].name headerfloat
+datatype[0].structtype[0].field[10].id[0]
+datatype[0].structtype[0].field[10].datatype 1
+datatype[0].structtype[0].field[11].name headerstring
+datatype[0].structtype[0].field[11].id[0]
+datatype[0].structtype[0].field[11].datatype 2
+datatype[0].structtype[0].field[12].name headerraw
+datatype[0].structtype[0].field[12].id[0]
+datatype[0].structtype[0].field[12].datatype 3
+datatype[0].structtype[0].field[13].name headerlong
+datatype[0].structtype[0].field[13].id[0]
+datatype[0].structtype[0].field[13].datatype 4
+datatype[0].structtype[0].field[14].name headerdouble
+datatype[0].structtype[0].field[14].id[0]
+datatype[0].structtype[0].field[14].datatype 5
+datatype[0].documenttype[0]
+datatype[1].id -851747595
+datatype[1].arraytype[0]
+datatype[1].weightedsettype[0]
+datatype[1].structtype[1]
+datatype[1].structtype[0].name benchmark.body
+datatype[1].structtype[0].version 0
+datatype[1].structtype[0].field[6]
+datatype[1].structtype[0].field[0].name bodyint
+datatype[1].structtype[0].field[0].id[0]
+datatype[1].structtype[0].field[0].datatype 0
+datatype[1].structtype[0].field[1].name bodyfloat
+datatype[1].structtype[0].field[1].id[0]
+datatype[1].structtype[0].field[1].datatype 1
+datatype[1].structtype[0].field[2].name bodystring
+datatype[1].structtype[0].field[2].id[0]
+datatype[1].structtype[0].field[2].datatype 2
+datatype[1].structtype[0].field[3].name bodyraw
+datatype[1].structtype[0].field[3].id[0]
+datatype[1].structtype[0].field[3].datatype 3
+datatype[1].structtype[0].field[4].name bodylong
+datatype[1].structtype[0].field[4].id[0]
+datatype[1].structtype[0].field[4].datatype 4
+datatype[1].structtype[0].field[5].name bodydouble
+datatype[1].structtype[0].field[5].id[0]
+datatype[1].structtype[0].field[5].datatype 5
+datatype[1].documenttype[0]
+datatype[2].id 2132196223
+datatype[2].arraytype[0]
+datatype[2].weightedsettype[0]
+datatype[2].structtype[0]
+datatype[2].documenttype[1]
+datatype[2].documenttype[0].name benchmark
+datatype[2].documenttype[0].version 0
+datatype[2].documenttype[0].inherits[0]
+datatype[2].documenttype[0].headerstruct -1007405344
+datatype[2].documenttype[0].bodystruct -851747595
diff --git a/vdslib/src/test/files/documenttypes.cfg b/vdslib/src/test/files/documenttypes.cfg
new file mode 100644
index 00000000000..d1c208f3a08
--- /dev/null
+++ b/vdslib/src/test/files/documenttypes.cfg
@@ -0,0 +1,126 @@
+enablecompression false
+documenttype[1]
+documenttype[0].id 2132196223
+documenttype[0].name "benchmark"
+documenttype[0].version 0
+documenttype[0].headerstruct -1007405344
+documenttype[0].bodystruct -851747595
+documenttype[0].inherits[0]
+documenttype[0].datatype[2]
+documenttype[0].datatype[0].id -1007405344
+documenttype[0].datatype[0].type STRUCT
+documenttype[0].datatype[0].array.element.id 0
+documenttype[0].datatype[0].map.key.id 0
+documenttype[0].datatype[0].map.value.id 0
+documenttype[0].datatype[0].wset.key.id 0
+documenttype[0].datatype[0].wset.createifnonexistent false
+documenttype[0].datatype[0].wset.removeifzero false
+documenttype[0].datatype[0].annotationref.annotation.id 0
+documenttype[0].datatype[0].sstruct.name "benchmark.header"
+documenttype[0].datatype[0].sstruct.version 0
+documenttype[0].datatype[0].sstruct.compression.type NONE
+documenttype[0].datatype[0].sstruct.compression.level 0
+documenttype[0].datatype[0].sstruct.compression.threshold 90
+documenttype[0].datatype[0].sstruct.compression.minsize 0
+documenttype[0].datatype[0].sstruct.field[15]
+documenttype[0].datatype[0].sstruct.field[0].name "headerdouble"
+documenttype[0].datatype[0].sstruct.field[0].id 225925695
+documenttype[0].datatype[0].sstruct.field[0].id_v6 1880905482
+documenttype[0].datatype[0].sstruct.field[0].datatype 5
+documenttype[0].datatype[0].sstruct.field[1].name "headerfloat"
+documenttype[0].datatype[0].sstruct.field[1].id 1625470423
+documenttype[0].datatype[0].sstruct.field[1].id_v6 1473207887
+documenttype[0].datatype[0].sstruct.field[1].datatype 1
+documenttype[0].datatype[0].sstruct.field[2].name "headerint"
+documenttype[0].datatype[0].sstruct.field[2].id 762302378
+documenttype[0].datatype[0].sstruct.field[2].id_v6 20914570
+documenttype[0].datatype[0].sstruct.field[2].datatype 0
+documenttype[0].datatype[0].sstruct.field[3].name "headerlong"
+documenttype[0].datatype[0].sstruct.field[3].id 1173959018
+documenttype[0].datatype[0].sstruct.field[3].id_v6 447443892
+documenttype[0].datatype[0].sstruct.field[3].datatype 4
+documenttype[0].datatype[0].sstruct.field[4].name "headerraw"
+documenttype[0].datatype[0].sstruct.field[4].id 391586263
+documenttype[0].datatype[0].sstruct.field[4].id_v6 1004217617
+documenttype[0].datatype[0].sstruct.field[4].datatype 3
+documenttype[0].datatype[0].sstruct.field[5].name "headerstring"
+documenttype[0].datatype[0].sstruct.field[5].id 788916026
+documenttype[0].datatype[0].sstruct.field[5].id_v6 104714882
+documenttype[0].datatype[0].sstruct.field[5].datatype 2
+documenttype[0].datatype[0].sstruct.field[6].name "maxbodydocsize"
+documenttype[0].datatype[0].sstruct.field[6].id 1712672954
+documenttype[0].datatype[0].sstruct.field[6].id_v6 843532182
+documenttype[0].datatype[0].sstruct.field[6].datatype 0
+documenttype[0].datatype[0].sstruct.field[7].name "maxheaderdocsize"
+documenttype[0].datatype[0].sstruct.field[7].id 1706483157
+documenttype[0].datatype[0].sstruct.field[7].id_v6 2053499986
+documenttype[0].datatype[0].sstruct.field[7].datatype 0
+documenttype[0].datatype[0].sstruct.field[8].name "minbodydocsize"
+documenttype[0].datatype[0].sstruct.field[8].id 655737763
+documenttype[0].datatype[0].sstruct.field[8].id_v6 1790708929
+documenttype[0].datatype[0].sstruct.field[8].datatype 0
+documenttype[0].datatype[0].sstruct.field[9].name "minheaderdocsize"
+documenttype[0].datatype[0].sstruct.field[9].id 138730086
+documenttype[0].datatype[0].sstruct.field[9].id_v6 1021372057
+documenttype[0].datatype[0].sstruct.field[9].datatype 0
+documenttype[0].datatype[0].sstruct.field[10].name "pregeneratedcontent"
+documenttype[0].datatype[0].sstruct.field[10].id 1358420191
+documenttype[0].datatype[0].sstruct.field[10].id_v6 107210372
+documenttype[0].datatype[0].sstruct.field[10].datatype 16
+documenttype[0].datatype[0].sstruct.field[11].name "seed"
+documenttype[0].datatype[0].sstruct.field[11].id 1584656448
+documenttype[0].datatype[0].sstruct.field[11].id_v6 2028175984
+documenttype[0].datatype[0].sstruct.field[11].datatype 0
+documenttype[0].datatype[0].sstruct.field[12].name "simplecontent"
+documenttype[0].datatype[0].sstruct.field[12].id 1986822798
+documenttype[0].datatype[0].sstruct.field[12].id_v6 1673731589
+documenttype[0].datatype[0].sstruct.field[12].datatype 16
+documenttype[0].datatype[0].sstruct.field[13].name "totaldoccount"
+documenttype[0].datatype[0].sstruct.field[13].id 428258253
+documenttype[0].datatype[0].sstruct.field[13].id_v6 400080120
+documenttype[0].datatype[0].sstruct.field[13].datatype 0
+documenttype[0].datatype[0].sstruct.field[14].name "totalusercount"
+documenttype[0].datatype[0].sstruct.field[14].id 1328467779
+documenttype[0].datatype[0].sstruct.field[14].id_v6 1421225290
+documenttype[0].datatype[0].sstruct.field[14].datatype 0
+documenttype[0].datatype[1].id -851747595
+documenttype[0].datatype[1].type STRUCT
+documenttype[0].datatype[1].array.element.id 0
+documenttype[0].datatype[1].map.key.id 0
+documenttype[0].datatype[1].map.value.id 0
+documenttype[0].datatype[1].wset.key.id 0
+documenttype[0].datatype[1].wset.createifnonexistent false
+documenttype[0].datatype[1].wset.removeifzero false
+documenttype[0].datatype[1].annotationref.annotation.id 0
+documenttype[0].datatype[1].sstruct.name "benchmark.body"
+documenttype[0].datatype[1].sstruct.version 0
+documenttype[0].datatype[1].sstruct.compression.type NONE
+documenttype[0].datatype[1].sstruct.compression.level 0
+documenttype[0].datatype[1].sstruct.compression.threshold 90
+documenttype[0].datatype[1].sstruct.compression.minsize 0
+documenttype[0].datatype[1].sstruct.field[6]
+documenttype[0].datatype[1].sstruct.field[0].name "bodydouble"
+documenttype[0].datatype[1].sstruct.field[0].id 409250413
+documenttype[0].datatype[1].sstruct.field[0].id_v6 896473220
+documenttype[0].datatype[1].sstruct.field[0].datatype 5
+documenttype[0].datatype[1].sstruct.field[1].name "bodyfloat"
+documenttype[0].datatype[1].sstruct.field[1].id 627746455
+documenttype[0].datatype[1].sstruct.field[1].id_v6 644475212
+documenttype[0].datatype[1].sstruct.field[1].datatype 1
+documenttype[0].datatype[1].sstruct.field[2].name "bodyint"
+documenttype[0].datatype[1].sstruct.field[2].id 1128436051
+documenttype[0].datatype[1].sstruct.field[2].id_v6 1680592860
+documenttype[0].datatype[1].sstruct.field[2].datatype 0
+documenttype[0].datatype[1].sstruct.field[3].name "bodylong"
+documenttype[0].datatype[1].sstruct.field[3].id 1947207690
+documenttype[0].datatype[1].sstruct.field[3].id_v6 82043035
+documenttype[0].datatype[1].sstruct.field[3].datatype 4
+documenttype[0].datatype[1].sstruct.field[4].name "bodyraw"
+documenttype[0].datatype[1].sstruct.field[4].id 864880572
+documenttype[0].datatype[1].sstruct.field[4].id_v6 2105006012
+documenttype[0].datatype[1].sstruct.field[4].datatype 3
+documenttype[0].datatype[1].sstruct.field[5].name "bodystring"
+documenttype[0].datatype[1].sstruct.field[5].id 316734404
+documenttype[0].datatype[1].sstruct.field[5].id_v6 474444010
+documenttype[0].datatype[1].sstruct.field[5].datatype 2
+documenttype[0].annotationtype[0]
diff --git a/vdslib/src/test/java/com/yahoo/vdslib/BucketDistributionTestCase.java b/vdslib/src/test/java/com/yahoo/vdslib/BucketDistributionTestCase.java
new file mode 100644
index 00000000000..33b8dd39e55
--- /dev/null
+++ b/vdslib/src/test/java/com/yahoo/vdslib/BucketDistributionTestCase.java
@@ -0,0 +1,111 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vdslib;
+
+import com.yahoo.document.BucketId;
+
+import java.util.Random;
+
+/**
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
+ */
+public class BucketDistributionTestCase extends junit.framework.TestCase {
+
+ private static final int NUM_COLUMNS = 16;
+ private static final int MIN_BUCKETBITS = 4;
+ private static final int MAX_BUCKETBITS = 9;
+
+ public void printExpected() {
+ System.out.println(" int[][] expected = new int[][] {");
+ for (int numBucketBits = MIN_BUCKETBITS; numBucketBits <= MAX_BUCKETBITS; ++numBucketBits) {
+ System.out.print(" new int[] {");
+ BucketDistribution bd = new BucketDistribution(NUM_COLUMNS, numBucketBits);
+ for (int i = 0; i < bd.getNumBuckets(); ++i) {
+ if (i % 32 == 0) {
+ System.out.println("");
+ System.out.print(" ");
+ }
+ System.out.print(bd.getColumn(new BucketId(16, i)));
+ if (i < bd.getNumBuckets() - 1) {
+ System.out.print(", ");
+ }
+ }
+ System.out.print(" }");
+ if (numBucketBits < MAX_BUCKETBITS) {
+ System.out.print(",");
+ }
+ System.out.println("");
+ }
+ System.out.println(" };");
+ }
+
+ public void testDistribution() {
+ int[][] expected = new int[][] {
+ new int[] {
+ 10, 11, 9, 6, 4, 8, 14, 1, 13, 2, 12, 3, 5, 7, 15, 0 },
+ new int[] {
+ 11, 12, 11, 13, 8, 13, 8, 9, 4, 5, 6, 12, 10, 15, 1, 1, 7, 9, 14, 2, 2, 14, 3, 3, 4, 5, 6, 7, 10, 15, 0, 0 },
+ new int[] {
+ 13, 13, 13, 13, 9, 11, 8, 9, 11, 14, 9, 11, 14, 14, 8, 10, 11, 14, 4, 5, 5, 6, 6, 7, 8, 10, 12, 15, 1, 1, 1, 1,
+ 6, 7, 8, 10, 12, 15, 2, 2, 2, 2, 12, 15, 3, 3, 3, 3, 4, 4, 4, 5, 5, 6, 7, 7, 9, 10, 12, 15, 0, 0, 0, 0 },
+ new int[] {
+ 14, 14, 14, 13, 11, 14, 14, 10, 13, 14, 10, 12, 8, 8, 9, 10, 9, 10, 11, 12, 13, 15, 11, 12, 13, 13, 15, 8, 8, 9, 10, 11,
+ 11, 12, 13, 15, 4, 4, 5, 5, 5, 5, 15, 6, 6, 7, 7, 7, 8, 9, 9, 10, 11, 12, 14, 15, 1, 1, 1, 1, 1, 1, 1, 1,
+ 6, 6, 6, 7, 7, 8, 8, 9, 10, 11, 12, 13, 15, 2, 2, 2, 2, 2, 2, 2, 2, 12, 13, 15, 3, 3, 3, 3, 3, 3, 3, 3,
+ 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 9, 9, 10, 11, 12, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0 },
+ new int[] {
+ 15, 14, 15, 15, 12, 14, 15, 12, 12, 11, 12, 13, 14, 13, 13, 13, 14, 15, 15, 9, 14, 9, 15, 10, 11, 11, 12, 8, 8, 8, 8, 9,
+ 9, 10, 10, 10, 11, 11, 12, 13, 13, 14, 10, 11, 11, 12, 13, 13, 14, 13, 13, 14, 15, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11,
+ 10, 10, 11, 11, 12, 13, 13, 14, 15, 4, 4, 4, 4, 15, 5, 5, 5, 5, 5, 5, 5, 15, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7,
+ 8, 8, 8, 9, 9, 9, 10, 10, 11, 11, 12, 12, 13, 14, 14, 15, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 11, 11, 12, 12, 13, 14, 14, 15, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 12, 12, 13, 14, 14, 15, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7,
+ 8, 8, 8, 9, 9, 9, 10, 10, 11, 11, 12, 12, 13, 14, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ new int[] {
+ 15, 15, 15, 15, 14, 14, 15, 13, 13, 13, 13, 13, 14, 14, 15, 12, 14, 15, 15, 11, 11, 12, 13, 13, 13, 14, 14, 15, 15, 10, 12, 12,
+ 12, 13, 13, 13, 14, 14, 15, 15, 9, 9, 9, 10, 10, 11, 11, 11, 12, 12, 12, 12, 13, 13, 14, 15, 15, 8, 8, 8, 8, 9, 9, 9,
+ 9, 9, 9, 10, 9, 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 14, 14, 14, 10, 10, 10, 11, 11, 11, 12, 12, 12, 12,
+ 13, 13, 14, 14, 14, 15, 15, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11,
+ 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15, 4, 4, 4, 4, 4, 4, 4, 15, 15, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 14, 14, 14, 15, 15, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 13, 13, 13, 14, 14, 15, 15, 15,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9,
+ 9, 9, 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 12, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 13, 13, 13, 14, 14, 15, 15, 15,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+ };
+
+ for (int numBucketBits = MIN_BUCKETBITS; numBucketBits <= MAX_BUCKETBITS; ++numBucketBits) {
+ BucketDistribution bd = new BucketDistribution(NUM_COLUMNS, numBucketBits);
+ assertEquals(NUM_COLUMNS, bd.getNumColumns());
+ assertEquals(1 << numBucketBits, bd.getNumBuckets());
+ for (int i = 0; i < bd.getNumBuckets(); ++i) {
+ assertEquals(expected[numBucketBits - MIN_BUCKETBITS][i], bd.getColumn(new BucketId(16, i)));
+ }
+ }
+ }
+
+ public void testNumBucketBits() {
+ Random rnd = new Random();
+
+ BucketDistribution bd = new BucketDistribution(1, 4);
+ for (int i = 0; i <= 0xf; ++i) {
+ assertEquals(0, bd.getColumn(new BucketId(32, (rnd.nextLong() << 4) & i)));
+ }
+
+ bd = new BucketDistribution(1, 8);
+ for (int i = 0; i <= 0xff; ++i) {
+ assertEquals(0, bd.getColumn(new BucketId(32, (rnd.nextLong() << 8) & i)));
+ }
+
+ bd = new BucketDistribution(1, 16);
+ for (int i = 0; i <= 0xffff; ++i) {
+ assertEquals(0, bd.getColumn(new BucketId(32, (rnd.nextLong() << 16) & i)));
+ }
+ }
+}
diff --git a/vdslib/src/test/java/com/yahoo/vdslib/DocumentListTestCase.java b/vdslib/src/test/java/com/yahoo/vdslib/DocumentListTestCase.java
new file mode 100644
index 00000000000..fd7ffbc409d
--- /dev/null
+++ b/vdslib/src/test/java/com/yahoo/vdslib/DocumentListTestCase.java
@@ -0,0 +1,135 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vdslib;
+
+import com.yahoo.document.*;
+import com.yahoo.document.datatypes.FloatFieldValue;
+import com.yahoo.document.datatypes.IntegerFieldValue;
+import com.yahoo.document.datatypes.StringFieldValue;
+import com.yahoo.document.serialization.DocumentSerializer;
+import com.yahoo.document.serialization.DocumentSerializerFactory;
+import com.yahoo.document.update.FieldUpdate;
+
+import java.io.EOFException;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+public class DocumentListTestCase extends junit.framework.TestCase {
+
+ @SuppressWarnings("deprecation")
+ public void testSelfSerializationAndWriteJavaFile() throws Exception {
+ DocumentTypeManager docMan = new DocumentTypeManager();
+ DocumentTypeManagerConfigurer.configure(docMan, "file:src/test/files/documentmanager.cfg");
+
+ DocumentType bmType = docMan.getDocumentType("benchmark");
+ DocumentPut put1 = new DocumentPut(bmType, "userdoc:foo:99999999:1");
+ put1.getDocument().setFieldValue("headerstring", "foo");
+ DocumentRemove doc2 = new DocumentRemove(new DocumentId("userdoc:foo:99999999:2"));
+ DocumentPut put3 = new DocumentPut(bmType, "userdoc:foo:99999999:3");
+ put3.getDocument().setFieldValue("bodyfloat", new FloatFieldValue(5.5f));
+
+
+ DocumentUpdate docUp = new DocumentUpdate(docMan.getDocumentType("benchmark"), new DocumentId("userdoc:foo:99999999:4"));
+ docUp.addFieldUpdate(FieldUpdate.createAssign(docUp.getType().getField("bodystring"), new StringFieldValue("ballooooo")));
+
+ List<Entry> entries = new ArrayList<Entry>();
+ entries.add(Entry.create(put1));
+ entries.add(Entry.create(doc2));
+ entries.add(Entry.create(put3));
+ entries.add(Entry.create(docUp));
+
+ DocumentList documentList = DocumentList.create(entries);
+
+ DocumentSerializer gbuf = DocumentSerializerFactory.create42();
+ gbuf.putInt(null, 1234); // Add some data to avoid special case where position() is 0 for buffer used.
+ int startPos = gbuf.getBuf().position();
+ documentList.serialize(gbuf);
+
+ int size = gbuf.getBuf().position() - startPos;
+ byte[] data = new byte[size];
+ gbuf.getBuf().position(startPos);
+ gbuf.getBuf().get(data);
+ FileOutputStream stream = new FileOutputStream("./src/test/files/documentlist-java.dat");
+ stream.write(data);
+ stream.close();
+
+ gbuf.getBuf().position(0);
+
+ DocumentList documentList2 = DocumentList.create(docMan, data);
+
+ assertEquals(4, documentList2.size());
+ Entry entry1 = documentList2.get(0);
+ assertEquals(0L, entry1.getTimestamp());
+ assertFalse(entry1.isBodyStripped());
+ assertFalse(entry1.isRemoveEntry());
+ assertFalse(entry1.isUpdateEntry());
+ assertTrue(entry1.getDocumentOperation() instanceof DocumentPut);
+ assertEquals(new StringFieldValue("foo"), ((DocumentPut) entry1.getDocumentOperation()).getDocument().getFieldValue("headerstring"));
+
+ Entry entry2 = documentList2.get(1);
+ assertEquals(0L, entry2.getTimestamp());
+ assertFalse(entry2.isBodyStripped());
+ assertTrue(entry2.isRemoveEntry());
+ assertFalse(entry2.isUpdateEntry());
+ assertTrue(entry2.getDocumentOperation() instanceof DocumentRemove);
+
+ Entry entry3 = documentList2.get(2);
+ assertEquals(0L, entry3.getTimestamp());
+ assertFalse(entry3.isBodyStripped());
+ assertFalse(entry3.isRemoveEntry());
+ assertFalse(entry3.isUpdateEntry());
+ assertTrue(entry3.getDocumentOperation() instanceof DocumentPut);
+ assertEquals(new FloatFieldValue(5.5f), ((DocumentPut) entry3.getDocumentOperation()).getDocument().getFieldValue("bodyfloat"));
+
+ Entry entry4 = documentList2.get(3);
+ assertEquals(0L, entry4.getTimestamp());
+ assertFalse(entry4.isBodyStripped());
+ assertFalse(entry4.isRemoveEntry());
+ assertTrue(entry4.isUpdateEntry());
+ assertTrue(entry4.getDocumentOperation() instanceof DocumentUpdate);
+ assertEquals(new StringFieldValue("ballooooo"),((DocumentUpdate) entry4.getDocumentOperation()).getFieldUpdate(0).getValueUpdate(0).getValue());
+ }
+
+ public void testContains() {
+ DocumentTypeManager manager = new DocumentTypeManager();
+ DocumentTypeManagerConfigurer.configure(manager, "file:src/test/files/documentmanager.cfg");
+
+ DocumentType bmType = manager.getDocumentType("benchmark");
+ DocumentPut put1 = new DocumentPut(bmType, "userdoc:foo:99999999:1");
+ DocumentRemove remove1 = new DocumentRemove(new DocumentId("userdoc:foo:99999999:2"));
+ DocumentPut put2 = new DocumentPut(bmType, "userdoc:foo:99999999:3");
+
+ List<Entry> entries = new ArrayList<Entry>();
+ entries.add(Entry.create(put1));
+ entries.add(Entry.create(remove1));
+ entries.add(Entry.create(put2));
+
+ DocumentList documentList = DocumentList.create(entries);
+
+ DocumentPut put3 = new DocumentPut(bmType, "userdoc:foo:99999999:1");
+ DocumentRemove remove2 = new DocumentRemove(new DocumentId("userdoc:foo:99999999:2"));
+ DocumentPut put4 = new DocumentPut(bmType, "userdoc:foo:99999999:3");
+
+ List<Entry> entries2 = new ArrayList<Entry>();
+ entries2.add(Entry.create(put3));
+ entries2.add(Entry.create(remove2));
+ entries2.add(Entry.create(put4));
+
+ DocumentList documentList2 = DocumentList.create(entries2);
+
+ assert(documentList.containsAll(documentList2));
+
+ Long t = put4.getDocument().getLastModified();
+ put4.getDocument().setLastModified(13L);
+ assert(!documentList.containsAll(documentList2));
+ put4.getDocument().setLastModified(t);
+
+ assert(documentList.containsAll(documentList2));
+
+ entries.remove(2);
+ assert(!documentList.containsAll(documentList2));
+
+ }
+}
diff --git a/vdslib/src/test/java/com/yahoo/vdslib/EntryTestCase.java b/vdslib/src/test/java/com/yahoo/vdslib/EntryTestCase.java
new file mode 100644
index 00000000000..2f1140e32b6
--- /dev/null
+++ b/vdslib/src/test/java/com/yahoo/vdslib/EntryTestCase.java
@@ -0,0 +1,51 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vdslib;
+
+import com.yahoo.document.Document;
+import com.yahoo.document.DocumentPut;
+import com.yahoo.document.DocumentType;
+import com.yahoo.document.DocumentTypeManager;
+import com.yahoo.document.DocumentTypeManagerConfigurer;
+
+/**
+ * @author banino
+ */
+public class EntryTestCase extends junit.framework.TestCase{
+
+ public void testEquals() {
+ DocumentTypeManager manager = new DocumentTypeManager();
+ DocumentTypeManagerConfigurer.configure(manager, "file:src/test/files/documentmanager.cfg");
+
+ DocumentType bmType = manager.getDocumentType("benchmark");
+ DocumentPut put1 = new DocumentPut(bmType, "userdoc:foo:99999999:1");
+ DocumentPut put2 = new DocumentPut(bmType, "userdoc:foo:99999999:2");
+
+ Entry entry1 = Entry.create(put1);
+ Entry entry2 = Entry.create(put1);
+ assert(entry1.equals(entry2));
+
+ Entry entry3 = Entry.create(put2);
+ assert(!entry1.equals(entry3));
+
+ }
+
+ public void testHashCode() {
+ DocumentTypeManager manager = new DocumentTypeManager();
+ DocumentTypeManagerConfigurer.configure(manager, "file:src/test/files/documentmanager.cfg");
+
+ DocumentType bmType = manager.getDocumentType("benchmark");
+ DocumentPut put1 = new DocumentPut(bmType, "userdoc:foo:99999999:1");
+ DocumentPut put2 = new DocumentPut(bmType, "userdoc:foo:99999999:2");
+
+ Entry entry1 = Entry.create(put1);
+ Entry entry2 = Entry.create(put1);
+ assert(entry1.hashCode() == entry2.hashCode());
+
+ Entry entry3 = Entry.create(put2);
+ assert(entry1.hashCode() != entry3.hashCode());
+
+ }
+
+
+
+}
diff --git a/vdslib/src/test/java/com/yahoo/vdslib/SearchResultTestCase.java b/vdslib/src/test/java/com/yahoo/vdslib/SearchResultTestCase.java
new file mode 100644
index 00000000000..eea51bf7787
--- /dev/null
+++ b/vdslib/src/test/java/com/yahoo/vdslib/SearchResultTestCase.java
@@ -0,0 +1,92 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vdslib;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @author balder
+ */
+public class SearchResultTestCase {
+
+ @Test
+ public void requireThatHitsOrderWell() {
+ SearchResult.Hit a = new SearchResult.Hit("a", 0);
+ SearchResult.Hit b = new SearchResult.Hit("b", 0.1);
+ SearchResult.Hit c = new SearchResult.Hit("c", 1.0);
+ SearchResult.Hit bb = new SearchResult.Hit("b2", 0.1);
+ assertTrue(a.compareTo(a) == 0);
+ assertTrue(a.compareTo(b) > 0);
+ assertTrue(a.compareTo(c) > 0);
+ assertTrue(b.compareTo(a) < 0);
+ assertTrue(b.compareTo(bb) == 0);
+ assertTrue(bb.compareTo(b) == 0);
+ assertTrue(b.compareTo(c) > 0);
+ assertTrue(c.compareTo(a) < 0);
+ assertTrue(c.compareTo(b) < 0);
+
+ byte [] b1 = {0x00};
+ byte [] b2 = {0x07};
+ byte [] b3 = {0x7f};
+ byte [] b4 = {(byte)0x80};
+ byte [] b5 = {(byte)0xb1};
+ byte [] b6 = {(byte)0xff};
+
+ assertEquals(0x00, b1[0]);
+ assertEquals(0x07, b2[0]);
+ assertEquals(0x7f, b3[0]);
+ assertEquals(0x80, ((int)b4[0]) & 0xff);
+ assertEquals(0xb1, ((int)b5[0]) & 0xff);
+ assertEquals(0xff, ((int)b6[0]) & 0xff);
+ SearchResult.Hit h1 = new SearchResult.HitWithSortBlob(a, b1);
+ SearchResult.Hit h2 = new SearchResult.HitWithSortBlob(a, b2);
+ SearchResult.Hit h3 = new SearchResult.HitWithSortBlob(a, b3);
+ SearchResult.Hit h4 = new SearchResult.HitWithSortBlob(a, b4);
+ SearchResult.Hit h5 = new SearchResult.HitWithSortBlob(a, b5);
+ SearchResult.Hit h6 = new SearchResult.HitWithSortBlob(a, b6);
+
+ assertTrue(h1.compareTo(h1) == 0);
+ assertTrue(h1.compareTo(h2) < 0);
+ assertTrue(h1.compareTo(h3) < 0);
+ assertTrue(h1.compareTo(h4) < 0);
+ assertTrue(h1.compareTo(h5) < 0);
+ assertTrue(h1.compareTo(h6) < 0);
+
+ assertTrue(h2.compareTo(h1) > 0);
+ assertTrue(h2.compareTo(h2) == 0);
+ assertTrue(h2.compareTo(h3) < 0);
+ assertTrue(h2.compareTo(h4) < 0);
+ assertTrue(h2.compareTo(h5) < 0);
+ assertTrue(h2.compareTo(h6) < 0);
+
+ assertTrue(h3.compareTo(h1) > 0);
+ assertTrue(h3.compareTo(h2) > 0);
+ assertTrue(h3.compareTo(h3) == 0);
+ assertTrue(h3.compareTo(h4) < 0);
+ assertTrue(h3.compareTo(h5) < 0);
+ assertTrue(h3.compareTo(h6) < 0);
+
+ assertTrue(h4.compareTo(h1) > 0);
+ assertTrue(h4.compareTo(h2) > 0);
+ assertTrue(h4.compareTo(h3) > 0);
+ assertTrue(h4.compareTo(h4) == 0);
+ assertTrue(h4.compareTo(h5) < 0);
+ assertTrue(h4.compareTo(h6) < 0);
+
+ assertTrue(h5.compareTo(h1) > 0);
+ assertTrue(h5.compareTo(h2) > 0);
+ assertTrue(h5.compareTo(h3) > 0);
+ assertTrue(h5.compareTo(h4) > 0);
+ assertTrue(h5.compareTo(h5) == 0);
+ assertTrue(h5.compareTo(h6) < 0);
+
+ assertTrue(h6.compareTo(h1) > 0);
+ assertTrue(h6.compareTo(h2) > 0);
+ assertTrue(h6.compareTo(h3) > 0);
+ assertTrue(h6.compareTo(h4) > 0);
+ assertTrue(h6.compareTo(h5) > 0);
+ assertTrue(h6.compareTo(h6) == 0);
+ }
+}
diff --git a/vdslib/src/test/java/com/yahoo/vdslib/VisitorOrderingTestCase.java b/vdslib/src/test/java/com/yahoo/vdslib/VisitorOrderingTestCase.java
new file mode 100644
index 00000000000..ed8f7d44d0d
--- /dev/null
+++ b/vdslib/src/test/java/com/yahoo/vdslib/VisitorOrderingTestCase.java
@@ -0,0 +1,40 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vdslib;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class VisitorOrderingTestCase {
+
+ @Test
+ public void testVisitorOrderingDefault() {
+ VisitorOrdering ordering = new VisitorOrdering();
+ assertEquals(VisitorOrdering.ASCENDING, ordering.getOrder());
+ assertEquals(0, ordering.getDivisionBits());
+ assertEquals(0, ordering.getWidthBits());
+ assertEquals(0, ordering.getOrderingStart());
+ assertEquals("+,0,0,0", ordering.toString());
+ }
+
+ @Test
+ public void testVisitorOrderingAscending() {
+ VisitorOrdering ordering = new VisitorOrdering(VisitorOrdering.ASCENDING);
+ assertEquals(VisitorOrdering.ASCENDING, ordering.getOrder());
+ assertEquals(0, ordering.getDivisionBits());
+ assertEquals(0, ordering.getWidthBits());
+ assertEquals(0, ordering.getOrderingStart());
+ assertEquals("+,0,0,0", ordering.toString());
+ }
+
+
+ @Test
+ public void testVisitorOrderingComplex() {
+ VisitorOrdering ordering = new VisitorOrdering(VisitorOrdering.DESCENDING, (long)3, (short)2, (short)1);
+ assertEquals(VisitorOrdering.DESCENDING, ordering.getOrder());
+ assertEquals(1, ordering.getDivisionBits());
+ assertEquals(2, ordering.getWidthBits());
+ assertEquals(3, ordering.getOrderingStart());
+ assertEquals("-,2,1,3", ordering.toString());
+ }
+}
diff --git a/vdslib/src/test/java/com/yahoo/vdslib/distribution/CrossPlatformTestFactory.java b/vdslib/src/test/java/com/yahoo/vdslib/distribution/CrossPlatformTestFactory.java
new file mode 100644
index 00000000000..2c28bfd1f8b
--- /dev/null
+++ b/vdslib/src/test/java/com/yahoo/vdslib/distribution/CrossPlatformTestFactory.java
@@ -0,0 +1,52 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vdslib.distribution;
+
+import java.io.*;
+
+/**
+ * Helper class to implement unit tests that should produce the same result in different implementations.
+ */
+public abstract class CrossPlatformTestFactory {
+ private final String directory;
+ private final String name;
+
+ public CrossPlatformTestFactory(String directory, String name) {
+ this.directory = directory;
+ this.name = name;
+ }
+
+ public String getName() { return name; }
+
+ public boolean loadTestResults() throws Exception {
+ File reference = new File(directory, name + ".reference.results");
+ if (!reference.exists()) {
+ return false;
+ }
+ BufferedReader br = new BufferedReader(new FileReader(reference));
+ StringBuilder sb = new StringBuilder();
+ try{
+ while(true) {
+ String line = br.readLine();
+ if (line == null) break;
+ sb.append(line);
+ }
+ parse(sb.toString());
+ } finally {
+ br.close();
+ }
+ return true;
+ }
+
+ public void recordTestResults() throws Exception {
+ File results = new File(directory, name + ".java.results");
+ FileWriter fw = new FileWriter(results);
+ try{
+ fw.write(serialize());
+ } finally {
+ fw.close();
+ }
+ }
+
+ public abstract String serialize() throws Exception;
+ public abstract void parse(String serialized) throws Exception;
+}
diff --git a/vdslib/src/test/java/com/yahoo/vdslib/distribution/DistributionTestCase.java b/vdslib/src/test/java/com/yahoo/vdslib/distribution/DistributionTestCase.java
new file mode 100644
index 00000000000..cdc7f8a5dd3
--- /dev/null
+++ b/vdslib/src/test/java/com/yahoo/vdslib/distribution/DistributionTestCase.java
@@ -0,0 +1,387 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vdslib.distribution;
+
+import com.yahoo.vespa.config.content.StorDistributionConfig;
+import com.yahoo.vdslib.state.ClusterState;
+import com.yahoo.document.BucketId;
+import com.yahoo.vdslib.state.NodeType;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
+import java.nio.file.StandardOpenOption;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Random;
+import java.util.Set;
+import java.util.Stack;
+
+public class DistributionTestCase extends junit.framework.TestCase {
+ private DistributionTestFactory test;
+ /** Build a set of buckets to test that should represent the entire bucket space well. */
+ private static List<BucketId> getTestBuckets() { return getTestBuckets(16); }
+ private static List<BucketId> getTestBuckets(int minUsedBits) {
+ List<BucketId> buckets = new ArrayList<>();
+ assertTrue(minUsedBits <= 16);
+ // Get a set of buckets from the same split level
+ for (int i=16; i<=18; ++i) {
+ for (int j=0; j<20; ++j) {
+ buckets.add(new BucketId(i, j));
+ }
+ }
+ // Get a few random buckets at every split level.
+ Random randomized = new Random(413);
+ long randValue = randomized.nextLong();
+ for (int i=minUsedBits; i<58; ++i) {
+ buckets.add(new BucketId(i, randValue));
+ }
+ randValue = randomized.nextLong();
+ for (int i=minUsedBits; i<58; ++i) {
+ buckets.add(new BucketId(i, randValue));
+ }
+ return Collections.unmodifiableList(buckets);
+ }
+ @Override
+ public void tearDown() throws Exception {
+ if (test != null) {
+ System.err.println("Verified " + test.getVerifiedTests() + " test results for test " + test.getName());
+ test.recordTestResults();
+ }
+ }
+ public void testSimple() {
+ test = new DistributionTestFactory("simple");
+ List<BucketId> buckets = getTestBuckets();
+ Integer nodes[] = { 6, 3, 4, 8, 8, 8, 8, 8, 8, 3 };
+ for (int i=0; i<buckets.size(); ++i) {
+ BucketId bucket = buckets.get(i);
+ DistributionTestFactory.Test t = test.recordResult(bucket).assertNodeCount(1);
+ if (i < nodes.length) t.assertNodeUsed(nodes[i]);
+ }
+ }
+ public void testDown() throws Exception {
+ test = new DistributionTestFactory("down")
+ .setUpStates("u")
+ .setClusterState(new ClusterState(
+ "distributor:10 .4.s:m .5.s:m .6.s:d .7.s:d .8.s:r .9.s:r"));
+ for (BucketId bucket : getTestBuckets()) {
+ assertTrue(test.recordResult(bucket).assertNodeCount(1).getNodes().get(0) < 4);
+ }
+ }
+
+ /**
+ * The java side runs unit tests first. Thus java side will generate the distribution tests that the C++ side will verify equality with.
+ * The tests serialized by the java side will be checked into version control, such that C++ side can test without java side. When one of the sides
+ * change, the failing side can be identified by checking if the serialized files are modified from what is checked into version control.
+ */
+ private void writeDistributionTest(String name, String clusterState, String distributionConfig) throws IOException, ParseException, Distribution.TooFewBucketBitsInUseException, Distribution.NoDistributorsAvailableException {
+ writeFileAtomically("src/tests/distribution/testdata/java_" + name + ".cfg", distributionConfig);
+ writeFileAtomically("src/tests/distribution/testdata/java_" + name + ".state", clusterState);
+ StringWriter sw = new StringWriter();
+ Distribution distribution = new Distribution("raw:" + distributionConfig);
+ ClusterState state = new ClusterState(clusterState);
+ long maxBucket = 1;
+ for (int distributionBits = 0; distributionBits <= 32; ++distributionBits) {
+ state.setDistributionBits(distributionBits);
+ RandomGen randomizer = new RandomGen(distributionBits);
+ for (int bucketIndex = 0; bucketIndex < 64; ++bucketIndex) {
+ if (bucketIndex >= maxBucket) break;
+ long bucketId = bucketIndex;
+ // Use random bucket if we dont test all
+ if (maxBucket > 64) {
+ bucketId = randomizer.nextLong();
+ }
+ BucketId bucket = new BucketId(distributionBits, bucketId);
+ for (int redundancy = 1; redundancy <= distribution.getRedundancy(); ++redundancy) {
+ int distributorIndex = distribution.getIdealDistributorNode(state, bucket, "uim");
+ sw.write(distributionBits + " " + bucket.withoutCountBits() + " " + redundancy + " " + distributorIndex + "\n");
+ }
+ }
+ maxBucket = maxBucket << 1;
+ }
+
+ writeFileAtomically("src/tests/distribution/testdata/java_" + name + ".distribution", sw.toString());
+ }
+
+ private void writeFileAtomically(String filename, String data) throws IOException {
+ FileSystem fs = FileSystems.getDefault();
+ Path filePath = fs.getPath(filename);
+ Path tempFilePath = fs.getPath(filename + ".tmp");
+
+ try (BufferedWriter bw = Files.newBufferedWriter(tempFilePath, StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) {
+ bw.write(data);
+ }
+
+ // Try to atomically move temporary file onto file. This is guaranteed to be atomic due to the files existing in the same file system
+ Files.move(tempFilePath, filePath, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE);
+ }
+
+
+ public void testWriteDistribution() throws IOException, ParseException, Distribution.TooFewBucketBitsInUseException, Distribution.NoDistributorsAvailableException {
+ String clusterState = "distributor:9";
+ String distributionConfig =
+ "redundancy 3\n" +
+ "group[4]\n" +
+ "group[0].index \"invalid\"\n" +
+ "group[0].name \"invalid\"\n" +
+ "group[0].partitions 1|2|*\n" +
+ "group[0].nodes[0]\n" +
+ "group[1].index 1\n" +
+ "group[1].capacity 2.0\n" +
+ "group[1].name group1\n" +
+ "group[1].partitions *\n" +
+ "group[1].nodes[3]\n" +
+ "group[1].nodes[0].index 0\n" +
+ "group[1].nodes[1].index 1\n" +
+ "group[1].nodes[2].index 2\n" +
+ "group[2].index 2\n" +
+ "group[2].capacity 3.0\n" +
+ "group[2].name group2\n" +
+ "group[2].partitions *\n" +
+ "group[2].nodes[3]\n" +
+ "group[2].nodes[0].index 3\n" +
+ "group[2].nodes[1].index 4\n" +
+ "group[2].nodes[2].index 5\n" +
+ "group[3].index 3\n" +
+ "group[3].capacity 5.0\n" +
+ "group[3].name group3\n" +
+ "group[3].partitions *\n" +
+ "group[3].nodes[3]\n" +
+ "group[3].nodes[0].index 6\n" +
+ "group[3].nodes[1].index 7\n" +
+ "group[3].nodes[2].index 8\n";
+ writeDistributionTest("depth2", clusterState, distributionConfig);
+
+ clusterState = "distributor:20 storage:20";
+ String complexDistributionConfig =
+ "redundancy 5\n" +
+ "group[7]\n" +
+ "group[0].partitions \"*|*\"\n" +
+ "group[0].index \"invalid\"\n" +
+ "group[0].name \"invalid\"\n" +
+ "group[0].nodes[0]\n" +
+ "group[1].partitions \"1|*\"\n" +
+ "group[1].index \"0\"\n" +
+ "group[1].name \"switch0\"\n" +
+ "group[1].nodes[0]\n" +
+ "group[2].partitions \"\"\n" +
+ "group[2].index \"0.0\"\n" +
+ "group[2].name \"rack0\"\n" +
+ "group[2].nodes[4]\n" +
+ "group[2].nodes[0].index 0\n" +
+ "group[2].nodes[1].index 1\n" +
+ "group[2].nodes[2].index 2\n" +
+ "group[2].nodes[3].index 3\n" +
+ "group[3].partitions \"\"\n" +
+ "group[3].index \"0.1\"\n" +
+ "group[3].name \"rack1\"\n" +
+ "group[3].nodes[4]\n" +
+ "group[3].nodes[0].index 8\n" +
+ "group[3].nodes[1].index 9\n" +
+ "group[3].nodes[2].index 14\n" +
+ "group[3].nodes[3].index 15\n" +
+ "group[4].partitions \"*\"\n" +
+ "group[4].index \"1\"\n" +
+ "group[4].name \"switch1\"\n" +
+ "group[4].nodes[0]\n" +
+ "group[5].partitions \"\"\n" +
+ "group[5].index \"1.0\"\n" +
+ "group[5].name \"rack0\"\n" +
+ "group[5].nodes[4]\n" +
+ "group[5].nodes[0].index 4\n" +
+ "group[5].nodes[1].index 5\n" +
+ "group[5].nodes[2].index 6\n" +
+ "group[5].nodes[3].index 17\n" +
+ "group[6].partitions \"\"\n" +
+ "group[6].index \"1.1\"\n" +
+ "group[6].name \"rack1\"\n" +
+ "group[6].nodes[4]\n" +
+ "group[6].nodes[0].index 10\n" +
+ "group[6].nodes[1].index 12\n" +
+ "group[6].nodes[2].index 13\n" +
+ "group[6].nodes[3].index 7";
+ writeDistributionTest("depth3", clusterState, complexDistributionConfig);
+
+ clusterState = "distributor:20 storage:20 .3.c:3 .7.c:2.5 .12.c:1.5";
+ writeDistributionTest("capacity", clusterState, complexDistributionConfig);
+
+ clusterState = "distributor:20 storage:20 .3.r:2 .7.r:3 .12.r:5";
+ writeDistributionTest("retired", clusterState, complexDistributionConfig);
+ }
+
+ public void testSplitBeyondSplitBitDoesntAffectDistribution() throws Exception {
+ Random randomized = new Random(7123161);
+ long val = randomized.nextLong();
+ test = new DistributionTestFactory("abovesplitbit");
+ for (int i=16; i<=58; ++i) {
+ test.recordResult(new BucketId(i, val)).assertNodeUsed(2);
+ }
+ }
+ public void testMinimalMovement() throws Exception {
+ test = new DistributionTestFactory("minimal-movement")
+ .setClusterState(new ClusterState("distributor:4 .2.s:d"));
+ DistributionTestFactory control = new DistributionTestFactory("minimal-movement-reference")
+ .setClusterState(new ClusterState("distributor:4"));
+ int moved = 0;
+ int staying = 0;
+ for (BucketId bucket : getTestBuckets()) {
+ DistributionTestFactory.Test org = control.recordResult(bucket).assertNodeCount(1);
+ DistributionTestFactory.Test res = test.recordResult(bucket).assertNodeCount(1);
+ if (org.getNodes().get(0) == 2) {
+ assertTrue(res.getNodes().get(0) != 2);
+ ++moved;
+ } else {
+ assertEquals(org, res);
+ ++staying;
+ }
+ }
+ assertEquals(63, moved);
+ assertEquals(81, staying);
+ }
+ public void testAllDistributionBits() throws Exception {
+ for (int distbits=0; distbits<=32; ++distbits) {
+ test = new DistributionTestFactory("distbit" + distbits)
+ .setClusterState(new ClusterState("bits:" + distbits + " distributor:10"));
+ List<BucketId> buckets = new ArrayList<>();
+ for (int i=0; i<100; ++i) {
+ buckets.add(new BucketId(distbits, i));
+ }
+ for (BucketId bucket : buckets) {
+ DistributionTestFactory.Test t = test.recordResult(bucket).assertNodeCount(1);
+ }
+ test.recordTestResults();
+ test = null;
+ }
+ }
+
+ private int getNodeCount(int depth, int branchCount, int nodesPerLeaf) {
+ if (depth <= 1) return branchCount * nodesPerLeaf;
+ int count = 0;
+ for (int i=0; i<branchCount; ++i) {
+ count += getNodeCount(depth - 1, branchCount, nodesPerLeaf);
+ }
+ return count;
+ }
+ private StorDistributionConfig.Builder buildHierarchicalConfig(
+ int redundancy, int branchCount, int depth, String partitions, int nodesPerLeaf)
+ {
+ StorDistributionConfig.Builder builder = new StorDistributionConfig.Builder()
+ .redundancy(redundancy);
+ builder.group(new StorDistributionConfig.Group.Builder()
+ .name("invalid").index("invalid").partitions(partitions));
+ Stack<Integer> nodeIndexes = new Stack<>();
+ for (int i=0, n=getNodeCount(depth, branchCount, nodesPerLeaf); i<n; ++i) nodeIndexes.push(i);
+ Collections.shuffle(nodeIndexes, new Random(123));
+ addLevel(builder, "top", "", branchCount, depth, partitions, nodesPerLeaf, nodeIndexes);
+ return builder;
+ }
+ private void addLevel(StorDistributionConfig.Builder builder, String namePrefix, String indexPrefix,
+ int branchCount, int depth, String partitions, int nodesPerLeaf,
+ Stack<Integer> nodes)
+ {
+ for (int i=0; i<branchCount; ++i) {
+ StorDistributionConfig.Group.Builder group
+ = new StorDistributionConfig.Group.Builder();
+ String gname = namePrefix + "." + i;
+ String index = (indexPrefix.isEmpty() ? "" + i : indexPrefix + "." + i);
+ group.name(gname).index(index);
+ if (depth <= 1) {
+ for (int j=0; j<nodesPerLeaf; ++j) {
+ group.nodes(new StorDistributionConfig.Group.Nodes.Builder().index(nodes.pop()));
+ }
+ } else {
+ group.partitions(partitions);
+ }
+ builder.group(group);
+ if (depth > 1) {
+ addLevel(builder, gname, index, branchCount, depth - 1, partitions, nodesPerLeaf, nodes);
+ }
+ }
+ }
+
+ public void testHierarchicalDistribution() throws Exception {
+ test = new DistributionTestFactory("hierarchical-grouping")
+ .setDistribution(buildHierarchicalConfig(6, 3, 1, "1|2|*", 3));
+ for (BucketId bucket : getTestBuckets()) {
+ test.recordResult(bucket).assertNodeCount(1);
+ }
+ }
+ public void testDistributorGroupTakeover() throws Exception {
+ test = new DistributionTestFactory("hierarchical-grouping-distributor-takeover")
+ .setDistribution(buildHierarchicalConfig(6, 3, 1, "1|2|*", 3).distributor_auto_ownership_transfer_on_whole_group_down(true))
+ .setNodeType(NodeType.DISTRIBUTOR)
+ .setClusterState(new ClusterState("distributor:2 storage:9"));
+ for (BucketId bucket : getTestBuckets()) {
+ test.recordResult(bucket).assertNodeCount(1);
+ }
+ }
+ public void testDistributorNoGroupTakeover() throws Exception {
+ test = new DistributionTestFactory("hierarchical-grouping-distributor-notakeover")
+ .setDistribution(buildHierarchicalConfig(6, 3, 1, "1|2|*", 3).distributor_auto_ownership_transfer_on_whole_group_down(false))
+ .setNodeType(NodeType.DISTRIBUTOR)
+ .setClusterState(new ClusterState("distributor:2 storage:9"));
+ int counts[] = new int[10];
+ int noneExisting = 0;
+ for (BucketId bucket : getTestBuckets()) {
+ DistributionTestFactory.Test t = test.recordResult(bucket);
+ List<Integer> nodes = t.getNodes();
+ if (nodes.isEmpty()) {
+ ++noneExisting;
+ t.assertFailure(DistributionTestFactory.Failure.NO_DISTRIBUTORS_AVAILABLE);
+ } else {
+ t.assertNodeCount(1);
+ for (int i : nodes) {
+ ++counts[i];
+ }
+ }
+ }
+ for (int i=2; i<10; ++i) {
+ assertEquals(0, counts[i]);
+ }
+ for (int i=0; i<2; ++i) {
+ assertTrue(counts[i] > 0);
+ }
+ assertEquals(15, noneExisting);
+ }
+ public void testHierarchicalDistributionDeep() throws Exception {
+ System.out.println(new StorDistributionConfig(buildHierarchicalConfig(8, 5, 3, "*|*", 3)));
+ test = new DistributionTestFactory("hierarchical-grouping-deep")
+ .setNodeCount(500)
+ .setDistribution(buildHierarchicalConfig(8, 5, 3, "*|*", 3));
+ for (BucketId bucket : getTestBuckets()) {
+ test.recordResult(bucket).assertNodeCount(1);
+ }
+ Set<ConfiguredNode> nodes = test.getDistribution().getNodes();
+ // Despite setNodeCount(500) above, the actual distribution config
+ // itself only has 375 actual leaf nodes.
+ assertEquals(375, nodes.size());
+ }
+ public void testHierarchicalDistributionCapacity() throws Exception {
+ StorDistributionConfig.Builder config = buildHierarchicalConfig(6, 3, 1, "1|*", 3);
+ config.group.get(1).capacity(3);
+ test = new DistributionTestFactory("group-capacity")
+ .setNodeCount(getNodeCount(1, 3, 3)).setDistribution(config);
+
+ int counts[] = new int[9];
+ for (int i=0; i<900; ++i) {
+ BucketId bucket = new BucketId(16, i);
+ ++counts[ test.recordResult(bucket).assertNodeCount(1).getNodes().get(0) ];
+ }
+ int groupCount = 0;
+ for (StorDistributionConfig.Group.Nodes.Builder n : config.group.get(1).nodes) {
+ StorDistributionConfig.Group.Nodes node = new StorDistributionConfig.Group.Nodes(n);
+ groupCount += counts[ node.index() ];
+ }
+ int avg3 = groupCount / 3;
+ int avg1 = (900 - groupCount) / 6;
+ double diff = 1.0 * avg3 / avg1;
+ assertTrue(Arrays.toString(counts) + ": Too large diff" + diff, diff < 3.1);
+ assertTrue(Arrays.toString(counts) + ": Too small diff" + diff, diff > 2.9);
+ }
+}
diff --git a/vdslib/src/test/java/com/yahoo/vdslib/distribution/DistributionTestFactory.java b/vdslib/src/test/java/com/yahoo/vdslib/distribution/DistributionTestFactory.java
new file mode 100644
index 00000000000..abd6ef70d35
--- /dev/null
+++ b/vdslib/src/test/java/com/yahoo/vdslib/distribution/DistributionTestFactory.java
@@ -0,0 +1,250 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vdslib.distribution;
+
+import com.yahoo.config.subscription.ConfigGetter;
+import com.yahoo.document.BucketId;
+import com.yahoo.vdslib.state.ClusterState;
+import com.yahoo.vdslib.state.Node;
+import com.yahoo.vdslib.state.NodeState;
+import com.yahoo.vdslib.state.NodeType;
+import com.yahoo.vespa.config.content.StorDistributionConfig;
+import junit.framework.TestCase;
+import org.codehaus.jettison.json.JSONArray;
+import org.codehaus.jettison.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class DistributionTestFactory extends CrossPlatformTestFactory {
+ private static final String testDirectory = "src/tests/distribution/testdata";
+ private int redundancy;
+ private int nodeCount;
+ private ClusterState state;
+ private StorDistributionConfig.Builder distributionConfig;
+ private NodeType nodeType;
+ private String upStates;
+
+ private int testsRecorded = 0;
+ private List<Test> results = new ArrayList<>();
+ private int testsVerified = 0;
+
+ enum Failure { NONE, TOO_FEW_BITS, NO_DISTRIBUTORS_AVAILABLE };
+
+ static public class Test {
+ private BucketId bucket;
+ private List<Integer> nodes;
+ private List<Integer> disks;
+ private Failure failure;
+
+ public Test(BucketId bucket) {
+ this.bucket = bucket;
+ nodes = new ArrayList<>();
+ disks = new ArrayList<>();
+ failure = Failure.NONE;
+ }
+
+ public boolean equals(Object other) {
+ if (!(other instanceof Test)) return false;
+ Test t = (Test) other;
+ return (bucket.equals(t.bucket)
+ && nodes.equals(t.nodes)
+ && failure.equals(t.failure));
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder().append(bucket.toString());
+ if (failure == Failure.NONE) {
+ sb.append(" [");
+ for (int i=0; i<nodes.size(); ++i) {
+ if (i != 0) sb.append(" ");
+ sb.append(nodes.get(i));
+ }
+ sb.append("]");
+ } else {
+ sb.append(' ').append(failure);
+ }
+ return sb.toString();
+ }
+
+ public List<Integer> getNodes() {
+ return nodes;
+ }
+ public List<Integer> getDisks() {
+ return disks;
+ }
+ public Integer getDiskForNode(int node) {
+ for (int i=0; i<nodes.size(); ++i) {
+ if (nodes.get(i) == node) return disks.get(i);
+ }
+ TestCase.fail("Node " + node + " is not in use: " + toString());
+ throw new IllegalStateException("Control should not reach here");
+ }
+
+ public Test assertFailure(Failure f) {
+ TestCase.assertEquals(f, failure);
+ return this;
+ }
+ public Test assertNodeCount(int count) {
+ if (count > 0) TestCase.assertEquals(toString(), Failure.NONE, failure);
+ TestCase.assertEquals(toString(), count, nodes.size());
+ return this;
+ }
+ public Test assertNodeUsed(int node) {
+ TestCase.assertEquals(toString(), Failure.NONE, failure);
+ TestCase.assertTrue(toString(), nodes.contains(node));
+ return this;
+ }
+ }
+
+ public DistributionTestFactory(String name) {
+ super(testDirectory, name);
+ try{
+ redundancy = 3;
+ nodeCount = 10;
+ state = new ClusterState("distributor:" + nodeCount);
+ distributionConfig = deserializeConfig(Distribution.getDefaultDistributionConfig(redundancy, nodeCount));
+ nodeType = NodeType.DISTRIBUTOR;
+ upStates = "uim";
+ loadTestResults();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static StorDistributionConfig.Builder deserializeConfig(String s) {
+ return new StorDistributionConfig.Builder(
+ new ConfigGetter<>(StorDistributionConfig.class).getConfig("raw:" + s));
+ }
+
+ public DistributionTestFactory setNodeCount(int count) throws Exception {
+ nodeCount = count;
+ distributionConfig = deserializeConfig(Distribution.getDefaultDistributionConfig(redundancy, nodeCount));
+ state = new ClusterState("distributor:" + nodeCount);
+ return this;
+ }
+
+ public DistributionTestFactory setClusterState(ClusterState state) {
+ this.state = state;
+ return this;
+ }
+
+ public DistributionTestFactory setDistribution(StorDistributionConfig.Builder d) {
+ this.distributionConfig = d;
+ return this;
+ }
+
+ public Distribution getDistribution() {
+ return new Distribution(new StorDistributionConfig(distributionConfig));
+ }
+
+ public DistributionTestFactory setNodeType(NodeType n) {
+ this.nodeType = n;
+ return this;
+ }
+
+ public DistributionTestFactory setUpStates(String up) {
+ this.upStates = up;
+ return this;
+ }
+
+ public int getVerifiedTests() {
+ return testsVerified;
+ }
+
+ void verifySame(Test javaTest, Test other) {
+ TestCase.assertEquals("Reference test " + testsRecorded + " differ.", other, javaTest);
+ ++testsVerified;
+ }
+
+ Test recordResult(BucketId bucket) {
+ Test t = new Test(bucket);
+ Distribution d = new Distribution(new StorDistributionConfig(distributionConfig));
+ try{
+ if (nodeType.equals(NodeType.DISTRIBUTOR)) {
+ int node = d.getIdealDistributorNode(state, bucket, upStates);
+ t.nodes.add(node);
+ } else {
+ for (int i : d.getIdealStorageNodes(state, bucket, upStates)) {
+ t.nodes.add(i);
+ NodeState ns = state.getNodeState(new Node(nodeType, i));
+ if (ns.getDiskCount() != 0) {
+ t.disks.add(d.getIdealDisk(ns, i, bucket));
+ } else {
+ t.disks.add(-1);
+ }
+ }
+ }
+ } catch (Distribution.TooFewBucketBitsInUseException e) {
+ t.failure = Failure.TOO_FEW_BITS;
+ } catch (Distribution.NoDistributorsAvailableException e) {
+ t.failure = Failure.NO_DISTRIBUTORS_AVAILABLE;
+ }
+ if (results.size() > testsRecorded) {
+ verifySame(t, results.get(testsRecorded));
+ } else {
+ results.add(t);
+ }
+ ++testsRecorded;
+ return t;
+ }
+
+ public String serialize() throws Exception {
+ JSONObject test = new JSONObject()
+ .put("cluster-state", state.toString())
+ .put("distribution", new StorDistributionConfig(distributionConfig).toString())
+ .put("node-type", nodeType.toString())
+ .put("redundancy", redundancy)
+ .put("node-count", nodeCount)
+ .put("up-states", upStates);
+ JSONArray results = new JSONArray();
+ for(Test t : this.results) {
+ JSONArray nodes = new JSONArray();
+ for (int i : t.nodes) {
+ nodes.put(i);
+ }
+ JSONArray disks = new JSONArray();
+ for (int i : t.disks) {
+ nodes.put(i);
+ }
+ JSONObject testResult = new JSONObject()
+ .put("bucket", Long.toHexString(t.bucket.getId()))
+ .put("nodes", nodes)
+ .put("failure", t.failure.toString());
+ if (nodeType == NodeType.STORAGE) {
+ testResult.put("disks", disks);
+ }
+ results.put(testResult);
+ }
+ test.put("result", results);
+ return test.toString(2);
+ }
+
+ public void parse(String serialized) throws Exception {
+ JSONObject json = new JSONObject(serialized);
+ upStates = json.getString("up-states");
+ nodeCount = json.getInt("redundancy");
+ redundancy = json.getInt("redundancy");
+ state = new ClusterState(json.getString("cluster-state"));
+ distributionConfig = deserializeConfig(json.getString("distribution"));
+ nodeType = NodeType.get(json.getString("node-type"));
+ JSONArray results = json.getJSONArray("result");
+ for (int i=0; i<results.length(); ++i) {
+ JSONObject result = results.getJSONObject(i);
+ Test t = new Test(new BucketId(Long.parseLong(result.getString("bucket"), 16)));
+ {
+ JSONArray nodes = result.getJSONArray("nodes");
+ for (int j=0; j<nodes.length(); ++j) {
+ t.nodes.add(nodes.getInt(j));
+ }
+ }
+ if (nodeType == NodeType.STORAGE) {
+ JSONArray disks = result.getJSONArray("disks");
+ for (int j=0; j<disks.length(); ++j) {
+ t.disks.add(disks.getInt(j));
+ }
+ }
+ t.failure = Failure.valueOf(result.getString("failure"));
+ this.results.add(t);
+ }
+ }
+}
diff --git a/vdslib/src/test/java/com/yahoo/vdslib/distribution/GroupTestCase.java b/vdslib/src/test/java/com/yahoo/vdslib/distribution/GroupTestCase.java
new file mode 100644
index 00000000000..9d65b33e975
--- /dev/null
+++ b/vdslib/src/test/java/com/yahoo/vdslib/distribution/GroupTestCase.java
@@ -0,0 +1,188 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vdslib.distribution;
+
+import java.text.ParseException;
+import java.util.*;
+
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertThat;
+
+public class GroupTestCase extends junit.framework.TestCase {
+
+ private void assertDistribution(String spec, int redundancy, String expectedResult) throws ParseException {
+ Group.Distribution distribution = new Group.Distribution(spec, redundancy);
+ assertEquals(spec, distribution.toString());
+ int[] resultArray = distribution.getRedundancyArray(redundancy);
+ StringBuffer sb = new StringBuffer();
+ for (int i=0; i<resultArray.length; ++i) {
+ if (i != 0) sb.append(',');
+ sb.append(resultArray[i]);
+ }
+ assertEquals("Spec: \"" + spec + "\", redundancy " + redundancy + " got unexpected result", expectedResult, sb.toString());
+ }
+
+ private void assertDistributionFailure(String spec, int redundancy, String expectedError) {
+ try{
+ Group.Distribution distribution = new Group.Distribution(spec, redundancy);
+ assertTrue("Failed to fail parsing of spec \"" + spec + "\", redundancy " + redundancy + " with failure: " + expectedError, false);
+ } catch (Exception e) {
+ assertEquals(expectedError, e.getMessage());
+ }
+ }
+
+ public void testStarConversion() throws ParseException {
+ assertDistribution("1|*|*", 5, "2,2,1");
+ assertDistribution("1|*|*", 6, "3,2,1");
+ assertDistribution("1|*|*", 3, "1,1,1");
+ assertDistribution("1|*|*", 2, "1,1");
+ assertDistribution("4|*", 3, "3");
+ assertDistribution("2|*", 3, "2,1");
+ assertDistribution("*|*", 3, "2,1");
+ assertDistribution("*|*|*", 4, "2,1,1");
+ assertDistribution("*|*|*", 5, "2,2,1");
+ assertDistribution("*|*|*|*", 5, "2,1,1,1");
+
+ assertDistributionFailure("2|*", 0, "The max redundancy must be a positive number in the range 1-255.");
+ assertDistributionFailure("*|2", 3, "Illegal distribution spec \"*|2\". Asterix specification must be tailing the specification.");
+ assertDistributionFailure("*|2|*", 3, "Illegal distribution spec \"*|2|*\". Asterix specification must be tailing the specification.");
+ assertDistributionFailure("0|*", 3, "Illegal distribution spec \"0|*\". Copy counts must be in the range 1-255.");
+ assertDistributionFailure("1|0|*", 3, "Illegal distribution spec \"1|0|*\". Copy counts must be in the range 1-255.");
+ assertDistributionFailure("1|a|*", 3, "Illegal distribution spec \"1|a|*\". Copy counts must be integer values in the range 1-255.");
+ assertDistributionFailure("1|999|*", 3, "Illegal distribution spec \"1|999|*\". Copy counts must be in the range 1-255.");
+ }
+
+ private void setNodes(Group g, String nodes) {
+ StringTokenizer st = new StringTokenizer(nodes, ",");
+ List<ConfiguredNode> nodeList = new ArrayList<>();
+ while (st.hasMoreTokens()) {
+ nodeList.add(new ConfiguredNode(Integer.parseInt(st.nextToken()), false));
+ }
+ g.setNodes(nodeList);
+ }
+
+ private void verifyUniqueHashes(Group g, Set<Integer> hashes) {
+ assertFalse(g.getName(), hashes.contains(g.getDistributionHash()));
+ hashes.add(g.getDistributionHash());
+ }
+
+ private Group buildGroupTree() throws ParseException {
+ Group root = new Group(5, "myroot", new Group.Distribution("2|*", 7));
+ List<Group> level_one = new ArrayList<Group>();
+ level_one.add(new Group(0, "br0", new Group.Distribution("1|1|*", 7)));
+ level_one.add(new Group(1, "br1", new Group.Distribution("*", 7)));
+ level_one.add(new Group(3, "br3", new Group.Distribution("8|*", 7)));
+ level_one.add(new Group(4, "br4", new Group.Distribution("1|*", 7)));
+ level_one.add(new Group(5, "br5", new Group.Distribution("*|*|*", 7)));
+ level_one.add(new Group(6, "br6", new Group.Distribution("*|*|*|*|*|*", 7)));
+ level_one.add(new Group(7, "br7", new Group.Distribution("*", 7)));
+ level_one.add(new Group(9, "br9", new Group.Distribution("1|*", 7)));
+ for(Group g : level_one) {
+ root.addSubGroup(g);
+ for (int i=0; i<5; ++i) {
+ Group child = new Group(i, g.getName() + "." + i);
+ g.addSubGroup(child);
+ List<ConfiguredNode> nodeList = new ArrayList<>();
+ for (int j=0; j<5; ++j) nodeList.add(new ConfiguredNode(g.getIndex() * 10 + j, false));
+ child.setNodes(nodeList);
+ }
+ }
+ // Create some irregularities
+ setNodes(level_one.get(3).getSubgroups().get(2), "19,7,8,17");
+ try{
+ Group br8 = new Group(5, "br8", new Group.Distribution("*", 5));
+ root.addSubGroup(br8);
+ assertTrue(false); // Should fail index 5 is in use at that level
+ } catch (Exception e) {
+ assertEquals("A subgroup with index 5 already exist.", e.getMessage());
+ }
+ try{
+ Group br8 = new Group(5, "br8");
+ Group br9 = new Group(2, "br9");
+ br8.addSubGroup(br9);
+ assertTrue(false); // Should fail as we want distribution to be set on non-leaf node
+ } catch (Exception e) {
+ assertEquals("Cannot add sub groups to a node without distribution set.", e.getMessage());
+ }
+ try{
+ Group br8 = new Group(5, "br8", new Group.Distribution("*", 5));
+ setNodes(br8, "1,2,3");
+ assertTrue(false); // Should fail as we can't have distribution on leaf node.
+ } catch (Exception e) {
+ assertEquals("Cannot add nodes to non-leaf group with distribution set", e.getMessage());
+ }
+ root.calculateDistributionHashValues();
+ Set<Integer> distributionHashes = new HashSet<Integer>();
+ verifyUniqueHashes(root, distributionHashes);
+ return root;
+ }
+
+ public void testNormalusage() throws ParseException {
+ Group root = new Group(2, "myroot", new Group.Distribution("*", 2));
+ assertFalse(root.isLeafGroup());
+
+ Group branch = new Group(5, "myleaf");
+ assertTrue(branch.isLeafGroup());
+
+ root = buildGroupTree();
+
+ String expected = "Group(name: myroot, index: 5, distribution: 2|*, subgroups: 8) {\n"
+ + " Group(name: br0, index: 0, distribution: 1|1|*, subgroups: 5) {\n"
+ + " Group(name: br0.0, index: 0, nodes( 0 1 2 3 4 )) {\n"
+ + " }\n"
+ + " Group(name: br0.1, index: 1, nodes( 0 1 2 3 4 )) {\n"
+ + " }\n"
+ + " Group(name: br0.2, index: 2, nodes( 0 1 2 3 4 )) {\n"
+ + " }\n"
+ + " Group(name: br0.3, index: 3, nodes( 0 1 2 3 4 )) {\n"
+ + " }\n"
+ + " Group(name: br0.4, index: 4, nodes( 0 1 2 3 4 )) {\n"
+ + " }\n"
+ + " }\n";
+ assertEquals(expected, root.toString().substring(0, expected.length()));
+
+ assertEquals("br5.br5.0", root.getGroupForNode(52).getPath());
+ }
+
+ private Group.Distribution dummyDistribution() throws Exception {
+ return new Group.Distribution("*", 1);
+ }
+
+ public void testRootGroupDoesNotIncludeGroupNameWhenNoChildren() {
+ Group g = new Group(0, "donkeykong");
+ assertThat(g.getUnixStylePath(), is("/"));
+ }
+
+ public void testChildNamesDoNotIncludeRootGroupName() throws Exception {
+ Group g = new Group(0, "donkeykong", dummyDistribution());
+ Group child = new Group(1, "mario");
+ g.addSubGroup(child);
+ assertThat(child.getUnixStylePath(), is("/mario"));
+ }
+
+ public void testNestedGroupsAreSlashSeparated() throws Exception {
+ Group g = new Group(0, "donkeykong", dummyDistribution());
+ Group mario = new Group(1, "mario", dummyDistribution());
+ Group toad = new Group(2, "toad");
+ mario.addSubGroup(toad);
+ g.addSubGroup(mario);
+
+ assertThat(toad.getUnixStylePath(), is("/mario/toad"));
+ }
+
+ public void testMultipleLeafGroupsAreEnumerated() throws Exception {
+ Group g = new Group(0, "donkeykong", dummyDistribution());
+ Group mario = new Group(1, "mario", dummyDistribution());
+ Group toad = new Group(2, "toad");
+ mario.addSubGroup(toad);
+ Group yoshi = new Group(3, "yoshi");
+ mario.addSubGroup(yoshi);
+ g.addSubGroup(mario);
+ Group luigi = new Group(4, "luigi");
+ g.addSubGroup(luigi);
+
+ assertThat(toad.getUnixStylePath(), is("/mario/toad"));
+ assertThat(yoshi.getUnixStylePath(), is("/mario/yoshi"));
+ assertThat(luigi.getUnixStylePath(), is("/luigi"));
+ }
+
+}
diff --git a/vdslib/src/test/java/com/yahoo/vdslib/state/ClusterStateTestCase.java b/vdslib/src/test/java/com/yahoo/vdslib/state/ClusterStateTestCase.java
new file mode 100644
index 00000000000..c058a7c9919
--- /dev/null
+++ b/vdslib/src/test/java/com/yahoo/vdslib/state/ClusterStateTestCase.java
@@ -0,0 +1,246 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vdslib.state;
+
+import java.text.ParseException;
+
+public class ClusterStateTestCase extends junit.framework.TestCase {
+
+ public void testSetNodeState() throws ParseException {
+ ClusterState state = new ClusterState("");
+ assertEquals("", state.toString());
+ state.setNodeState(new Node(NodeType.DISTRIBUTOR, 3), new NodeState(NodeType.DISTRIBUTOR, State.UP));
+ assertEquals("distributor:4 .0.s:d .1.s:d .2.s:d", state.toString());
+ state.setNodeState(new Node(NodeType.DISTRIBUTOR, 1), new NodeState(NodeType.DISTRIBUTOR, State.UP));
+ assertEquals("distributor:4 .0.s:d .2.s:d", state.toString());
+ state.setNodeState(new Node(NodeType.DISTRIBUTOR, 3), new NodeState(NodeType.DISTRIBUTOR, State.DOWN));
+ assertEquals("distributor:2 .0.s:d", state.toString());
+ state.setNodeState(new Node(NodeType.DISTRIBUTOR, 4), new NodeState(NodeType.DISTRIBUTOR, State.UP));
+ assertEquals("distributor:5 .0.s:d .2.s:d .3.s:d", state.toString());
+ state.setNodeState(new Node(NodeType.STORAGE, 0), new NodeState(NodeType.STORAGE, State.UP).setDiskCount(4));
+ assertEquals("distributor:5 .0.s:d .2.s:d .3.s:d storage:1", state.toString());
+ state.setNodeState(new Node(NodeType.STORAGE, 0), new NodeState(NodeType.STORAGE, State.UP).setDiskCount(4).setDiskState(1, new DiskState(State.DOWN)));
+ assertEquals("distributor:5 .0.s:d .2.s:d .3.s:d storage:1 .0.d:4 .0.d.1.s:d", state.toString());
+ }
+
+ public void testClone() throws ParseException {
+ ClusterState state = new ClusterState("");
+ state.setNodeState(new Node(NodeType.DISTRIBUTOR, 1), new NodeState(NodeType.DISTRIBUTOR, State.UP).setDescription("available"));
+ state.setNodeState(new Node(NodeType.STORAGE, 0), new NodeState(NodeType.STORAGE, State.UP).setCapacity(1.2).setReliability(2));
+ state.setNodeState(new Node(NodeType.STORAGE, 2), new NodeState(NodeType.STORAGE, State.UP).setDiskCount(2).setDiskState(1, new DiskState(State.DOWN)));
+ ClusterState other = state.clone();
+ assertEquals(state.toString(true), other.toString(true));
+ assertEquals(state.toString(false), other.toString(false));
+ assertEquals(state, other);
+ }
+
+ public void testEquals() throws ParseException {
+ ClusterState state = new ClusterState("");
+
+ assertEquals(state, new ClusterState(""));
+
+ assertEquals(state, new ClusterState("version:0"));
+ assertEquals(state, new ClusterState("cluster:u"));
+ assertEquals(state, new ClusterState("bits:16"));
+ assertEquals(state, new ClusterState("storage:0"));
+ assertEquals(state, new ClusterState("distributor:0"));
+
+ assertFalse(state.equals(new ClusterState("version:1")));
+ assertFalse(state.equals(new ClusterState("cluster:d")));
+ assertFalse(state.equals(new ClusterState("bits:20")));
+ assertFalse(state.equals(new ClusterState("storage:1")));
+ assertFalse(state.equals(new ClusterState("distributor:1")));
+
+ {
+ ClusterState state1 = new ClusterState("distributor:3 .1.s:d .2.s:m storage:3 .1.s:i .2.s:r");
+ ClusterState state2 = new ClusterState("distributor:3 .1.s:d .2.s:m storage:3 .1.s:i .2.s:m");
+ assertFalse(state1.equals(state2));
+ assertFalse(state1.similarTo(state2));
+ }
+
+ {
+ ClusterState state1 = new ClusterState("cluster:d");
+ ClusterState state2 = new ClusterState("cluster:d version:1 bits:20 distributor:1 storage:1 .0.s:d");
+ assertFalse(state1.equals(state2));
+ assertTrue(state1.similarTo(state2));
+ }
+
+ {
+ ClusterState state1 = new ClusterState("distributor:3 .1.s:d .2.s:m storage:3 .1.s:i .2.s:r");
+ ClusterState state2 = new ClusterState("distributor:3 storage:3");
+ assertFalse(state1.equals(state2));
+ assertFalse(state1.similarTo(state2));
+ }
+
+ assertFalse(state.equals("class not instance of ClusterState"));
+ assertFalse(state.similarTo("class not instance of ClusterState"));
+
+ assertEquals(state, state);
+ assertTrue(state.similarTo(state));
+ }
+
+ public void testTextDiff() throws ParseException {
+ ClusterState state1 = new ClusterState("distributor:9 storage:4");
+ ClusterState state2 = new ClusterState("distributor:7 storage:6");
+ ClusterState state3 = new ClusterState("distributor:9 storage:2");
+
+ assertEquals("storage: [4: Down => Up, 5: Down => Up], distributor: [7: Up => Down, 8: Up => Down]", state1.getTextualDifference(state2));
+ assertEquals("storage: [2: Up => Down, 3: Up => Down, 4: Up => Down, 5: Up => Down], distributor: [7: Down => Up, 8: Down => Up]", state2.getTextualDifference(state3));
+
+ state2.setDistributionBits(21);
+ state1.setVersion(123);
+ state1.setNodeState(new Node(NodeType.STORAGE, 2), new NodeState(NodeType.STORAGE, State.INITIALIZING).setInitProgress(0.2).setDiskCount(2).setDescription("Booting"));
+ state2.setOfficial(true);
+
+ assertEquals("version: 123 => 0, bits: 16 => 21, official: false => true, storage: [2: [Initializing => Up, disks: 2 => 0, description: Booting => ], 4: Down => Up, 5: Down => Up], distributor: [7: Up => Down, 8: Up => Down]", state1.getTextualDifference(state2));
+ }
+
+ public void testHtmlDiff() throws ParseException {
+ ClusterState state1 = new ClusterState("distributor:9 storage:4");
+ ClusterState state2 = new ClusterState("distributor:7 storage:6");
+ ClusterState state3 = new ClusterState("distributor:9 storage:2");
+
+ assertEquals("storage: [4: Down => Up, 5: Down => Up], distributor: [7: Up => Down, 8: Up => Down]", state1.getTextualDifference(state2));
+ assertEquals("storage: [<br>\n" +
+ "&nbsp;4: <b>Down</b> =&gt; <b>Up</b>, <br>\n" +
+ "&nbsp;5: <b>Down</b> =&gt; <b>Up</b><br>\n" +
+ "], distributor: [<br>\n" +
+ "&nbsp;7: <b>Up</b> =&gt; <b>Down</b>, <br>\n" +
+ "&nbsp;8: <b>Up</b> =&gt; <b>Down</b><br>\n" +
+ "]", state1.getHtmlDifference(state2));
+ assertEquals("storage: [2: Up => Down, 3: Up => Down, 4: Up => Down, 5: Up => Down], distributor: [7: Down => Up, 8: Down => Up]", state2.getTextualDifference(state3));
+ assertEquals("storage: [<br>\n" +
+ "&nbsp;2: <b>Up</b> =&gt; <b>Down</b>, <br>\n" +
+ "&nbsp;3: <b>Up</b> =&gt; <b>Down</b>, <br>\n" +
+ "&nbsp;4: <b>Up</b> =&gt; <b>Down</b>, <br>\n" +
+ "&nbsp;5: <b>Up</b> =&gt; <b>Down</b><br>\n" +
+ "], distributor: [<br>\n" +
+ "&nbsp;7: <b>Down</b> =&gt; <b>Up</b>, <br>\n" +
+ "&nbsp;8: <b>Down</b> =&gt; <b>Up</b><br>\n" +
+ "]", state2.getHtmlDifference(state3));
+
+ state1.setVersion(123);
+ state1.setNodeState(new Node(NodeType.STORAGE, 2), new NodeState(NodeType.STORAGE, State.INITIALIZING).setInitProgress(0.2).setDiskCount(2).setDescription("Booting"));
+ state2.setDistributionBits(21);
+ state2.setOfficial(true);
+ assertEquals("version: 123 => 0, bits: 16 => 21, official: false => true, storage: [2: [Initializing => Up, disks: 2 => 0, description: Booting => ], 4: Down => Up, 5: Down => Up], distributor: [7: Up => Down, 8: Up => Down]", state1.getTextualDifference(state2));
+ assertEquals("version: 123 =&gt; 0, bits: 16 =&gt; 21, official: false =&gt; true, storage: [<br>\n" +
+ "&nbsp;2: [<b>Initializing</b> =&gt; <b>Up</b>, disks: 2 =&gt; 0, description: Booting =&gt; ], <br>\n" +
+ "&nbsp;4: <b>Down</b> =&gt; <b>Up</b>, <br>\n" +
+ "&nbsp;5: <b>Down</b> =&gt; <b>Up</b><br>\n" +
+ "], distributor: [<br>\n" +
+ "&nbsp;7: <b>Up</b> =&gt; <b>Down</b>, <br>\n" +
+ "&nbsp;8: <b>Up</b> =&gt; <b>Down</b><br>\n" +
+ "]", state1.getHtmlDifference(state2));
+ }
+
+
+ public void testParser() throws ParseException {
+ ClusterState state = new ClusterState("distributor:2 storage:17 .2.s:d .13.s:r m:cluster\\x20message");
+ assertEquals("cluster message", state.getDescription());
+
+ for (int i = 0; i < state.getNodeCount(NodeType.STORAGE); i++) {
+ if (i == 2)
+ assertEquals("d", state.getNodeState(new Node(NodeType.STORAGE, i)).getState().serialize());
+ if (i == 13)
+ assertEquals("r", state.getNodeState(new Node(NodeType.STORAGE, i)).getState().serialize());
+ if (i != 2 && i != 13)
+ assertEquals("u", state.getNodeState(new Node(NodeType.STORAGE, i)).getState().serialize());
+ }
+
+ assertEquals("distributor:2 storage:17 .2.s:d .13.s:r", state.toString());
+ assertEquals("distributor:2", new ClusterState("distributor:2 storage:0").toString());
+ assertEquals("storage:2", new ClusterState("storage:2 .0.d:3 .1.d:4").toString());
+ assertEquals("distributor:2 .1.t:3 storage:2", new ClusterState("whatever:4 distributor:2 .1.t:3 storage:2").toString());
+ assertEquals("distributor:2 storage:2", new ClusterState(": distributor:2 storage:2 .0:d cbadkey:u bbadkey:2 vbadkey:2 mbadkey:message dbadkey:5 sbadkey:6 unknownkey:somevalue").toString());
+
+ try {
+ new ClusterState("badtokenwithoutcolon");
+ assertTrue("Should fail", false);
+ } catch (Exception e) {}
+ try {
+ new ClusterState(".0.s:d");
+ assertTrue("Should fail", false);
+ } catch (Exception e) {}
+ try {
+ new ClusterState("cluster:badvalue");
+ assertTrue("Should fail", false);
+ } catch (Exception e) {}
+ try {
+ new ClusterState("cluster:m");
+ assertTrue("Should fail", false);
+ } catch (Exception e) {}
+ try {
+ new ClusterState("version:badvalue");
+ assertTrue("Should fail", false);
+ } catch (Exception e) {}
+ try {
+ new ClusterState("distributor:badvalue");
+ assertTrue("Should fail", false);
+ } catch (Exception e) {}
+ try {
+ new ClusterState("storage:badvalue");
+ assertTrue("Should fail", false);
+ } catch (Exception e) {}
+ try {
+ new ClusterState("distributor:2 .3.s:d");
+ assertTrue("Should fail", false);
+ } catch (Exception e) {}
+ try {
+ new ClusterState("storage:2 .3.s:d");
+ assertTrue("Should fail", false);
+ } catch (Exception e) {}
+ }
+
+ public void testCapacityExponential() throws ParseException {
+
+ ClusterState state = new ClusterState("distributor:27 storage:170 .2.s:d .13.c:3E-8 .13.s:r");
+ assertEquals(3E-8, state.getNodeState(new Node(NodeType.STORAGE, 13)).getCapacity());
+ }
+
+ public void testCapacityExponentialCpp() throws ParseException {
+ ClusterState state = new ClusterState("distributor:27 storage:170 .2.s:d .13.c:3e-08 .13.s:r");
+ assertEquals(3E-8, state.getNodeState(new Node(NodeType.STORAGE, 13)).getCapacity());
+ }
+
+ public void testSetState() throws ParseException {
+ ClusterState state = new ClusterState("distributor:2 storage:2");
+ state.setNodeState(new Node(NodeType.DISTRIBUTOR, 0), new NodeState(NodeType.DISTRIBUTOR, State.DOWN));
+
+ assertEquals("distributor:2 .0.s:d storage:2", state.toString());
+ }
+
+ public void testVersionAndClusterStates() throws ParseException {
+ ClusterState state = new ClusterState("version:4 cluster:i distributor:2 .1.s:i storage:2 .0.s:i .0.i:0.345");
+ assertEquals(4, state.getVersion());
+ assertEquals(State.INITIALIZING, state.getClusterState());
+ assertEquals(0.345, state.getNodeState(new Node(NodeType.STORAGE, 0)).getInitProgress(), 0.000001);
+ state.setClusterState(State.DOWN);
+ state.setVersion(5);
+ state.setDistributionBits(12);
+ assertEquals("version:5 cluster:d bits:12 distributor:2 .1.s:i .1.i:1.0 storage:2 .0.s:i .0.i:0.345", state.toString());
+ }
+
+ public void testNotRemovingCommentedDownNodesAtEnd() throws ParseException {
+ ClusterState state = new ClusterState("");
+ state.setNodeState(new Node(NodeType.DISTRIBUTOR, 0), new NodeState(NodeType.DISTRIBUTOR, State.UP));
+ state.setNodeState(new Node(NodeType.DISTRIBUTOR, 1), new NodeState(NodeType.DISTRIBUTOR, State.UP));
+ state.setNodeState(new Node(NodeType.STORAGE, 0), new NodeState(NodeType.STORAGE, State.UP));
+ state.setNodeState(new Node(NodeType.STORAGE, 1), new NodeState(NodeType.STORAGE, State.UP));
+ state.setNodeState(new Node(NodeType.STORAGE, 2), new NodeState(NodeType.STORAGE, State.UP));
+ assertEquals("distributor:2 storage:3", state.toString());
+ state.setNodeState(new Node(NodeType.STORAGE, 2), new NodeState(NodeType.STORAGE, State.DOWN).setDescription("Took it down"));
+ state.setNodeState(new Node(NodeType.DISTRIBUTOR, 1), new NodeState(NodeType.DISTRIBUTOR, State.DOWN).setDescription("Took it down"));
+ assertEquals("distributor:2 .1.s:d .1.m:Took\\x20it\\x20down storage:3 .2.s:d .2.m:Took\\x20it\\x20down", state.toString(true));
+ assertEquals("distributor:1 storage:2", state.toString(false));
+ }
+
+ public void testWhitespace() throws ParseException {
+ ClusterState state = new ClusterState("distributor:2\n .1.t:3\nstorage:2\n\t.0.s:i \r\f.1.s:m");
+ assertEquals(2, state.getNodeCount(NodeType.DISTRIBUTOR));
+ assertEquals(2, state.getNodeCount(NodeType.STORAGE));
+ assertEquals(new NodeState(NodeType.DISTRIBUTOR, State.UP), state.getNodeState(new Node(NodeType.DISTRIBUTOR, 0)));
+ assertEquals(new NodeState(NodeType.DISTRIBUTOR, State.UP).setStartTimestamp(3), state.getNodeState(new Node(NodeType.DISTRIBUTOR, 1)));
+ assertEquals(new NodeState(NodeType.STORAGE, State.INITIALIZING), state.getNodeState(new Node(NodeType.STORAGE, 0)));
+ assertEquals(new NodeState(NodeType.STORAGE, State.MAINTENANCE), state.getNodeState(new Node(NodeType.STORAGE, 1)));
+ }
+}
diff --git a/vdslib/src/test/java/com/yahoo/vdslib/state/DiskStateTestCase.java b/vdslib/src/test/java/com/yahoo/vdslib/state/DiskStateTestCase.java
new file mode 100644
index 00000000000..9d78b54a681
--- /dev/null
+++ b/vdslib/src/test/java/com/yahoo/vdslib/state/DiskStateTestCase.java
@@ -0,0 +1,106 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vdslib.state;
+
+import java.text.ParseException;
+
+public class DiskStateTestCase extends junit.framework.TestCase {
+
+ public void testEquals() {
+ DiskState d1 = new DiskState(State.UP, "", 1);
+ DiskState d2 = new DiskState(State.UP, "", 2);
+ DiskState d3 = new DiskState(State.DOWN, "Failed disk", 1);
+ DiskState d4 = new DiskState(State.DOWN, "IO error", 1);
+ DiskState d5 = new DiskState(State.UP, "", 1);
+ DiskState d6 = new DiskState(State.UP, "", 2);
+ DiskState d7 = new DiskState(State.DOWN, "Failed disk", 1);
+ DiskState d8 = new DiskState(State.DOWN, "IO error", 1);
+
+ assertEquals(d1, d5);
+ assertEquals(d2, d6);
+ assertEquals(d3, d7);
+ assertEquals(d4, d8);
+
+ assertFalse(d1.equals(d2));
+ assertFalse(d1.equals(d3));
+ assertFalse(d1.equals(d4));
+
+ assertFalse(d2.equals(d1));
+ assertFalse(d2.equals(d3));
+ assertFalse(d2.equals(d4));
+
+ assertFalse(d3.equals(d1));
+ assertFalse(d3.equals(d2));
+ assertEquals(d3, d4);
+
+ assertFalse(d4.equals(d1));
+ assertFalse(d4.equals(d2));
+ assertEquals(d4, d3);
+
+ assertFalse(d1.equals("class not instance of Node"));
+ }
+
+ public void testSerialization() throws ParseException {
+ DiskState d = new DiskState();
+ DiskState other = new DiskState(d.serialize("", true));
+ assertEquals(d, other);
+ assertEquals(d.toString(), other.toString());
+ assertEquals(State.UP, other.getState());
+ assertEquals(1.0, other.getCapacity());
+ assertEquals("", other.getDescription());
+ assertEquals("s:u", d.serialize("", false));
+ assertEquals("s:u", d.serialize("", true));
+ assertEquals("", d.serialize(".0.", false));
+ assertEquals("", d.serialize(".0.", true));
+
+ assertEquals(d, new DiskState(": s:u sbadkey:somevalue cbadkey:somevalue mbadkey:somevalue unknwonkey:somevalue"));
+
+ d = new DiskState(State.UP, "Slow disk", 1.0);
+ other = new DiskState(d.serialize("", true));
+ assertEquals(d, other);
+ assertEquals(d.toString(), other.toString());
+ assertEquals(State.UP, other.getState());
+ assertEquals(1.0, other.getCapacity());
+ assertEquals("Slow disk", other.getDescription());
+ assertEquals("s:u", d.serialize("", false));
+ assertEquals("s:u m:Slow\\x20disk", d.serialize("", true));
+ assertEquals("", d.serialize(".0.", false));
+ assertEquals(".0.m:Slow\\x20disk", d.serialize(".0.", true));
+
+ d = new DiskState(State.DOWN, "Failed disk", 2.0);
+ other = new DiskState(d.serialize("", true));
+ assertEquals(d, other);
+ assertEquals(d.toString(), other.toString());
+ assertEquals(State.DOWN, other.getState());
+ assertEquals(2.0, other.getCapacity());
+ assertEquals("Failed disk", other.getDescription());
+ assertEquals("s:d c:2.0", d.serialize("", false));
+ assertEquals("s:d c:2.0 m:Failed\\x20disk", d.serialize("", true));
+ assertEquals(".0.s:d .0.c:2.0", d.serialize(".0.", false));
+ assertEquals(".0.s:d .0.c:2.0 .0.m:Failed\\x20disk", d.serialize(".0.", true));
+
+ try {
+ new DiskState(State.MAINTENANCE);
+ assertTrue("Method expected to throw IllegalArgumentException", false);
+ } catch (IllegalArgumentException e) {
+ assertEquals("State " + State.MAINTENANCE + " is not a valid disk state.", e.getMessage());
+ }
+ try {
+ new DiskState(State.UP, "", -1);
+ assertTrue("Method expected to throw IllegalArgumentException", false);
+ } catch (IllegalArgumentException e) {
+ assertEquals("Negative capacity makes no sense.", e.getMessage());
+ }
+ try {
+ new DiskState("nocolon");
+ assertTrue("Method expected to throw ParseException", false);
+ } catch (ParseException e) {
+ assertEquals("Token nocolon does not contain ':': nocolon", e.getMessage());
+ }
+ try {
+ new DiskState("s:d c:badvalue");
+ assertTrue("Method expected to throw ParseException", false);
+ } catch (ParseException e) {
+ assertEquals("Illegal disk capacity 'badvalue'. Capacity must be a positive floating point number", e.getMessage());
+ }
+ }
+}
diff --git a/vdslib/src/test/java/com/yahoo/vdslib/state/NodeStateTestCase.java b/vdslib/src/test/java/com/yahoo/vdslib/state/NodeStateTestCase.java
new file mode 100644
index 00000000000..63137a92c7b
--- /dev/null
+++ b/vdslib/src/test/java/com/yahoo/vdslib/state/NodeStateTestCase.java
@@ -0,0 +1,231 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vdslib.state;
+
+import java.text.ParseException;
+import java.util.List;
+
+public class NodeStateTestCase extends junit.framework.TestCase {
+
+ public void testOrdinals() {
+ NodeType nt = NodeType.STORAGE;
+
+ // All states are above maintenance
+ assertFalse(new NodeState(nt, State.MAINTENANCE).above(new NodeState(nt, State.MAINTENANCE)));
+ assertTrue(new NodeState(nt, State.DOWN).above(new NodeState(nt, State.MAINTENANCE)));
+ assertTrue(new NodeState(nt, State.STOPPING).above(new NodeState(nt, State.MAINTENANCE)));
+ assertTrue(new NodeState(nt, State.INITIALIZING).above(new NodeState(nt, State.MAINTENANCE)));
+ assertTrue(new NodeState(nt, State.RETIRED).above(new NodeState(nt, State.MAINTENANCE)));
+ assertTrue(new NodeState(nt, State.UP).above(new NodeState(nt, State.MAINTENANCE)));
+
+ // Most are above down
+ assertFalse(new NodeState(nt, State.MAINTENANCE).above(new NodeState(nt, State.DOWN)));
+ assertFalse(new NodeState(nt, State.DOWN).above(new NodeState(nt, State.DOWN)));
+ assertTrue(new NodeState(nt, State.STOPPING).above(new NodeState(nt, State.DOWN)));
+ assertTrue(new NodeState(nt, State.INITIALIZING).above(new NodeState(nt, State.DOWN)));
+ assertTrue(new NodeState(nt, State.RETIRED).above(new NodeState(nt, State.DOWN)));
+ assertTrue(new NodeState(nt, State.UP).above(new NodeState(nt, State.DOWN)));
+
+ // Only up is above retired
+ assertFalse(new NodeState(nt, State.MAINTENANCE).above(new NodeState(nt, State.RETIRED)));
+ assertFalse(new NodeState(nt, State.DOWN).above(new NodeState(nt, State.RETIRED)));
+ assertFalse(new NodeState(nt, State.STOPPING).above(new NodeState(nt, State.RETIRED)));
+ assertFalse(new NodeState(nt, State.INITIALIZING).above(new NodeState(nt, State.RETIRED)));
+ assertFalse(new NodeState(nt, State.RETIRED).above(new NodeState(nt, State.RETIRED)));
+ assertTrue(new NodeState(nt, State.UP).above(new NodeState(nt, State.RETIRED)));
+ }
+
+ public void testTrivialitiesToIncreaseCoverage() throws ParseException {
+ NodeState ns = new NodeState(NodeType.STORAGE, State.UP);
+ assertEquals(1, ns.getReliability());
+ assertEquals(false, ns.isAnyDiskDown());
+
+ assertEquals(ns.setReliability(2).serialize(), NodeState.deserialize(NodeType.STORAGE, "r:2").serialize());
+ assertEquals(ns.setDiskCount(1).serialize(), NodeState.deserialize(NodeType.STORAGE, "r:2 d:1").serialize());
+ assertEquals(ns.setReliability(1).serialize(), NodeState.deserialize(NodeType.STORAGE, "d:1").serialize());
+
+ assertEquals(ns.setDiskState(0, new DiskState(State.DOWN, "", 1)), NodeState.deserialize(NodeType.STORAGE, "s:u d:1 d.0.s:d"));
+ assertEquals(ns, NodeState.deserialize(NodeType.STORAGE, "s:u d:1 d.0:d"));
+ }
+
+ public void testDiskState() throws ParseException {
+ NodeState ns = NodeState.deserialize(NodeType.STORAGE, "s:m");
+ assertEquals(new DiskState(State.UP, "", 1), ns.getDiskState(0));
+ assertEquals(new DiskState(State.UP, "", 1), ns.getDiskState(1));
+ assertEquals(new DiskState(State.UP, "", 1), ns.getDiskState(100));
+
+ ns.setDiskCount(2).setDiskState(1, new DiskState(State.DOWN, "bad disk", 1));
+ assertEquals(new DiskState(State.UP, "", 1), ns.getDiskState(0));
+ assertEquals(new DiskState(State.DOWN, "bad disk", 1), ns.getDiskState(1));
+
+ List<DiskState> diskStates = ns.getDiskStates();
+ assertEquals(2, diskStates.size());
+ for (int i=0; i<diskStates.size(); i++) {
+ DiskState diskState = diskStates.get(i);
+ if (i==1) {
+ assertEquals(new DiskState(State.DOWN, "bad disk", 1), diskState);
+ } else {
+ assertEquals(new DiskState(State.UP, "", 1), diskState);
+ }
+ }
+
+ try {
+ NodeState.deserialize(NodeType.STORAGE, "s:m").setDiskCount(-1);
+ assertTrue("Should fail", false);
+ } catch (Exception e) {}
+ try {
+ NodeState.deserialize(NodeType.STORAGE, "s:m").setDiskState(1, new DiskState(State.DOWN, "bad disk", 1));
+ assertTrue("Should fail", false);
+ } catch (Exception e) {}
+ try {
+ NodeState.deserialize(NodeType.STORAGE, "s:m").setDiskCount(2).setDiskState(1, new DiskState(State.DOWN, "bad disk", 1)).getDiskState(100);
+ assertTrue("Should fail", false);
+ } catch (Exception e) {}
+ }
+
+ public void testSerialization() throws ParseException {
+ NodeState ns = new NodeState(NodeType.STORAGE, State.MAINTENANCE);
+ assertEquals("s:m", ns.serialize(false));
+ assertEquals("s:m", ns.serialize(true));
+ assertEquals(ns, NodeState.deserialize(NodeType.STORAGE, "s:m"));
+ assertEquals(ns, NodeState.deserialize(NodeType.STORAGE, "s:m c:1.0 r:1 d:0 t:0"));
+
+ NodeState nsd = new NodeState(NodeType.DISTRIBUTOR, State.MAINTENANCE);
+ assertEquals(nsd, NodeState.deserialize(NodeType.DISTRIBUTOR, "s:m"));
+ assertEquals(nsd, NodeState.deserialize(NodeType.DISTRIBUTOR, "s:m c:2.0 r:2 d:2")); // Ignore capacity, reliability, and disk count for distributors
+
+ assertEquals(ns, NodeState.deserialize(NodeType.STORAGE, ": s:m sbadkey:u bbadkey:2 cbadkey:2.0 rbadkey:2 ibadkey:0.5 tbadkey:2 mbadkey:message dbadkey:2 unknownkey:somevalue"));
+ try {
+ NodeState.deserialize(NodeType.STORAGE, "s:m badtokenwithoutcolon");
+ assertTrue("Should fail", false);
+ } catch (Exception e) {}
+ try {
+ NodeState.deserialize(NodeType.STORAGE, "s:m c:badvalue");
+ assertTrue("Should fail", false);
+ } catch (Exception e) {}
+ try {
+ NodeState.deserialize(NodeType.STORAGE, "s:m r:badvalue");
+ assertTrue("Should fail", false);
+ } catch (Exception e) {}
+ try {
+ NodeState.deserialize(NodeType.STORAGE, "s:m i:badvalue");
+ assertTrue("Should fail", false);
+ } catch (Exception e) {}
+ try {
+ NodeState.deserialize(NodeType.STORAGE, "s:m t:badvalue");
+ assertTrue("Should fail", false);
+ } catch (Exception e) {}
+ try {
+ NodeState.deserialize(NodeType.STORAGE, "s:m t:-1");
+ assertTrue("Should fail", false);
+ } catch (Exception e) {}
+ try {
+ NodeState.deserialize(NodeType.STORAGE, "s:m d:badvalue");
+ assertTrue("Should fail", false);
+ } catch (Exception e) {}
+ try {
+ NodeState.deserialize(NodeType.STORAGE, "s:m d.badkey:badvalue");
+ assertTrue("Should fail", false);
+ } catch (Exception e) {}
+ try {
+ NodeState.deserialize(NodeType.STORAGE, "s:m d.1:badindex");
+ assertTrue("Should fail", false);
+ } catch (Exception e) {}
+
+ ns = new NodeState(NodeType.STORAGE, State.UP).setDescription("Foo bar");
+ assertEquals("", ns.serialize(2, false));
+ assertEquals("m:Foo\\x20bar", ns.serialize(false));
+ assertEquals("m:Foo\\x20bar", ns.serialize(true));
+
+ ns = new NodeState(NodeType.STORAGE, State.MAINTENANCE).setDescription("Foo bar").setCapacity(1.2).setDiskCount(4)
+ .setMinUsedBits(12).setStartTimestamp(5).setDiskState(1, new DiskState(State.DOWN, "bad disk", 1))
+ .setDiskState(3, new DiskState(State.UP, "", 2));
+ assertEquals(".2.s:m .2.c:1.2 .2.t:5 .2.d:4 .2.d.1.s:d .2.d.3.c:2.0", ns.serialize(2, false));
+ assertEquals("s:m c:1.2 t:5 b:12 d:4 d.1.s:d d.3.c:2.0 m:Foo\\x20bar", ns.serialize(false));
+ assertEquals("s:m c:1.2 t:5 b:12 d:4 d.1.s:d d.1.m:bad\\x20disk d.3.c:2.0 m:Foo\\x20bar", ns.serialize(true));
+ NodeState ns2 = NodeState.deserialize(NodeType.STORAGE, "s:m c:1.2 t:5 b:12 d:4 d.1.s:d d.1.m:bad\\x20disk d.3.c:2.0 m:Foo\\x20bar");
+ assertEquals(ns, ns2);
+
+ NodeState copy1 = NodeState.deserialize(NodeType.STORAGE, ns.serialize(false));
+ NodeState copy2 = NodeState.deserialize(NodeType.STORAGE, ns.serialize(true));
+ assertEquals(ns, copy1);
+ assertEquals(ns, copy2);
+ assertEquals(copy1, copy2);
+ assertEquals(ns.serialize(false), copy1.serialize(false));
+ assertEquals(ns.serialize(false), copy2.serialize(false));
+ assertEquals(ns.serialize(true), copy2.serialize(true));
+ }
+
+ public void testSimilarTo() {
+ {
+ NodeState ns1 = new NodeState(NodeType.STORAGE, State.INITIALIZING).setInitProgress(0);
+ NodeState ns2 = new NodeState(NodeType.STORAGE, State.INITIALIZING).setInitProgress(NodeState.getListingBucketsInitProgressLimit() / 2);
+ NodeState ns3 = new NodeState(NodeType.STORAGE, State.INITIALIZING).setInitProgress(NodeState.getListingBucketsInitProgressLimit());
+ NodeState ns4 = new NodeState(NodeType.STORAGE, State.INITIALIZING).setInitProgress(NodeState.getListingBucketsInitProgressLimit() * 2);
+ assertTrue(ns1.similarTo(ns2));
+ assertFalse(ns2.similarTo(ns3));
+ assertTrue(ns3.similarTo(ns4));
+
+ assertFalse(ns1.equals(ns2));
+ assertFalse(ns2.equals(ns3));
+ assertFalse(ns3.equals(ns4));
+
+ assertFalse(ns1.equals("class not instance of NodeState"));
+ assertFalse(ns1.similarTo("class not instance of NodeState"));
+ }
+ {
+ NodeState ns1 = new NodeState(NodeType.STORAGE, State.UP).setMinUsedBits(16);
+ NodeState ns2 = new NodeState(NodeType.STORAGE, State.UP).setMinUsedBits(18);
+ assertTrue(ns1.similarTo(ns2));
+ assertFalse(ns1.equals(ns2));
+ }
+ {
+ NodeState ns = new NodeState(NodeType.STORAGE, State.MAINTENANCE);
+ NodeState ns2Disks = new NodeState(NodeType.STORAGE, State.MAINTENANCE).setDiskCount(2);
+ assertEquals(ns, ns2Disks);
+ assertEquals(ns2Disks, ns);
+ assertTrue(ns.similarTo(ns2Disks));
+ assertTrue(ns2Disks.similarTo(ns));
+
+ ns2Disks.getDiskState(0).setState(State.DOWN);
+ assertFalse(ns.equals(ns2Disks));
+ assertFalse(ns2Disks.equals(ns));
+ assertFalse(ns.similarTo(ns2Disks));
+ assertFalse(ns2Disks.similarTo(ns));
+ }
+ }
+
+ public void testReadableOutput() {
+ // toString() and getDiff() is mostly there just to make good error reports when unit tests fails. Make sure toString() is actually run with no test failures
+ // to make sure coverage doesn't complain when no test is failing.
+ NodeState ns = new NodeState(NodeType.STORAGE, State.MAINTENANCE);
+ String expected = "Maintenance => Up";
+ assertEquals(expected, ns.getTextualDifference(new NodeState(NodeType.STORAGE, State.UP)).substring(0, expected.length()));
+
+ NodeState ns1 = new NodeState(NodeType.STORAGE, State.MAINTENANCE).setDescription("Foo bar").setCapacity(1.2).setReliability(2).setDiskCount(4)
+ .setMinUsedBits(12).setStartTimestamp(5).setDiskState(1, new DiskState(State.DOWN, "bad disk", 1))
+ .setDiskState(3, new DiskState(State.UP, "", 2));
+ ns1.toString();
+ ns1.toString(true);
+ expected = "Maintenance => Up, capacity: 1.2 => 1.0, reliability: 2 => 1, minUsedBits: 12 => 16, startTimestamp: 5 => 0, disks: 4 => 0, description: Foo bar => ";
+ assertEquals(expected, ns1.getTextualDifference(new NodeState(NodeType.STORAGE, State.UP)).substring(0, expected.length()));
+ }
+
+ public void testValidInClusterState() {
+ try{
+ new NodeState(NodeType.DISTRIBUTOR, State.UNKNOWN).verifyValidInSystemState(NodeType.DISTRIBUTOR);
+ assertTrue("Should not be valid", false);
+ } catch (Exception e) {}
+ try{
+ new NodeState(NodeType.DISTRIBUTOR, State.UP).setCapacity(3).verifyValidInSystemState(NodeType.DISTRIBUTOR);
+ assertTrue("Should not be valid", false);
+ } catch (Exception e) {}
+ try{
+ new NodeState(NodeType.DISTRIBUTOR, State.UP).setReliability(3).verifyValidInSystemState(NodeType.DISTRIBUTOR);
+ assertTrue("Should not be valid", false);
+ } catch (Exception e) {}
+ try{
+ new NodeState(NodeType.DISTRIBUTOR, State.UP).setDiskCount(2).verifyValidInSystemState(NodeType.DISTRIBUTOR);
+ assertTrue("Should not be valid", false);
+ } catch (Exception e) {}
+ }
+}
diff --git a/vdslib/src/test/java/com/yahoo/vdslib/state/NodeTest.java b/vdslib/src/test/java/com/yahoo/vdslib/state/NodeTest.java
new file mode 100644
index 00000000000..ce2ff075d78
--- /dev/null
+++ b/vdslib/src/test/java/com/yahoo/vdslib/state/NodeTest.java
@@ -0,0 +1,87 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vdslib.state;
+
+/**
+ *
+ */
+public class NodeTest extends junit.framework.TestCase {
+
+ public void testEquals() {
+ Node n1 = new Node(NodeType.STORAGE, 6);
+ Node n2 = new Node(NodeType.STORAGE, 7);
+ Node n3 = new Node(NodeType.DISTRIBUTOR, 6);
+ Node n4 = new Node(NodeType.DISTRIBUTOR, 7);
+ Node n5 = new Node(NodeType.STORAGE, 6);
+ Node n6 = new Node(NodeType.STORAGE, 7);
+ Node n7 = new Node(NodeType.DISTRIBUTOR, 6);
+ Node n8 = new Node(NodeType.DISTRIBUTOR, 7);
+
+ assertEquals(n1, n5);
+ assertEquals(n2, n6);
+ assertEquals(n3, n7);
+ assertEquals(n4, n8);
+ assertEquals(n1, n1);
+ assertEquals(n2, n2);
+ assertEquals(n3, n3);
+ assertEquals(n4, n4);
+
+ assertFalse(n1.equals(n2));
+ assertFalse(n1.equals(n3));
+ assertFalse(n1.equals(n4));
+
+ assertFalse(n2.equals(n1));
+ assertFalse(n2.equals(n3));
+ assertFalse(n2.equals(n4));
+
+ assertFalse(n3.equals(n1));
+ assertFalse(n3.equals(n2));
+ assertFalse(n3.equals(n4));
+
+ assertFalse(n4.equals(n1));
+ assertFalse(n4.equals(n2));
+ assertFalse(n4.equals(n3));
+
+ assertFalse(n1.equals("class not instance of Node"));
+ }
+
+ public void testSerialization() {
+ Node n = new Node(NodeType.STORAGE, 6);
+ Node other = new Node(n.toString());
+ assertEquals(n, other);
+ assertEquals(n.hashCode(), other.hashCode());
+
+ n = new Node(NodeType.DISTRIBUTOR, 5);
+ other = new Node(n.toString());
+ assertEquals(n, other);
+ assertEquals(n.hashCode(), other.hashCode());
+
+ try {
+ new Node("nodewithoutdot");
+ assertTrue("Method expected to throw IllegalArgumentException", false);
+ } catch (IllegalArgumentException e) {
+ assertEquals("Not a legal node string 'nodewithoutdot'.", e.getMessage());
+ }
+ try {
+ new Node("fleetcontroller.0");
+ assertTrue("Method expected to throw IllegalArgumentException", false);
+ } catch (IllegalArgumentException e) {
+ assertEquals("Unknown node type 'fleetcontroller'. Legal values are 'storage' and 'distributor'.", e.getMessage());
+ }
+ try {
+ new Node("storage.badindex");
+ assertTrue("Method expected to throw NumberFormatException", false);
+ } catch (NumberFormatException e) {
+ assertEquals("For input string: \"badindex\"", e.getMessage());
+ }
+ }
+
+ public void testMaySetWantedState() {
+ assertTrue(State.UP.maySetWantedStateForThisNodeState(State.DOWN));
+ assertTrue(State.UP.maySetWantedStateForThisNodeState(State.MAINTENANCE));
+ assertFalse(State.DOWN.maySetWantedStateForThisNodeState(State.UP));
+ assertTrue(State.DOWN.maySetWantedStateForThisNodeState(State.MAINTENANCE));
+ assertFalse(State.MAINTENANCE.maySetWantedStateForThisNodeState(State.UP));
+ assertFalse(State.MAINTENANCE.maySetWantedStateForThisNodeState(State.DOWN));
+ }
+
+}
diff --git a/vdslib/src/tests/.gitignore b/vdslib/src/tests/.gitignore
new file mode 100644
index 00000000000..b1f63a7fe4f
--- /dev/null
+++ b/vdslib/src/tests/.gitignore
@@ -0,0 +1,6 @@
+.depend
+Makefile
+datadistributiontest
+test.vlog
+testrunner
+vdslib_testrunner_app
diff --git a/vdslib/src/tests/CMakeLists.txt b/vdslib/src/tests/CMakeLists.txt
new file mode 100644
index 00000000000..484ea533ccc
--- /dev/null
+++ b/vdslib/src/tests/CMakeLists.txt
@@ -0,0 +1,12 @@
+# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_executable(vdslib_testrunner_app
+ SOURCES
+ testrunner.cpp
+ DEPENDS
+ vdslib_containertest
+ vdslib_testdistribution
+ vdslib_teststate
+ vdslib_testthread
+ vdslib
+)
+vespa_add_test(NAME vdslib_testrunner_app COMMAND vdslib_testrunner_app)
diff --git a/vdslib/src/tests/bucketdistribution/.gitignore b/vdslib/src/tests/bucketdistribution/.gitignore
new file mode 100644
index 00000000000..583460ae288
--- /dev/null
+++ b/vdslib/src/tests/bucketdistribution/.gitignore
@@ -0,0 +1,3 @@
+*.So
+.depend
+Makefile
diff --git a/vdslib/src/tests/bucketdistribution/CMakeLists.txt b/vdslib/src/tests/bucketdistribution/CMakeLists.txt
new file mode 100644
index 00000000000..511a791d924
--- /dev/null
+++ b/vdslib/src/tests/bucketdistribution/CMakeLists.txt
@@ -0,0 +1,6 @@
+# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_library(vdslib_bucketdistributiontest
+ SOURCES
+ bucketdistributiontest.cpp
+ DEPENDS
+)
diff --git a/vdslib/src/tests/bucketdistribution/bucketdistributiontest.cpp b/vdslib/src/tests/bucketdistribution/bucketdistributiontest.cpp
new file mode 100644
index 00000000000..8daf089957f
--- /dev/null
+++ b/vdslib/src/tests/bucketdistribution/bucketdistributiontest.cpp
@@ -0,0 +1,116 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#include <vespa/fastos/fastos.h>
+#include <vespa/log/log.h>
+LOG_SETUP(".bucketdistributiontest");
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <vespa/vdslib/bucketdistribution.h>
+
+using namespace vdslib;
+
+class BucketDistributionTest : public CppUnit::TestFixture {
+public:
+ void setUp() { }
+ void tearDown() { }
+ void testDistribution();
+ void testNumBucketBits();
+
+public:
+ CPPUNIT_TEST_SUITE(BucketDistributionTest);
+ CPPUNIT_TEST(testDistribution);
+ CPPUNIT_TEST(testNumBucketBits);
+ CPPUNIT_TEST_SUITE_END();
+
+private:
+ void assertDistribution(uint32_t numColumns, uint32_t numBucketBits, const uint32_t expected[]);
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(BucketDistributionTest);
+
+void BucketDistributionTest::testDistribution()
+{
+ LOG(info, "testDistribution");
+ const uint32_t expected4[] = {
+ 10, 11, 9, 6, 4, 8, 14, 1, 13, 2, 12, 3, 5, 7, 15, 0 };
+ assertDistribution(16, 4, expected4);
+
+ const uint32_t expected5[] = {
+ 11, 12, 11, 13, 8, 13, 8, 9, 4, 5, 6, 12, 10, 15, 1, 1, 7, 9, 14, 2, 2, 14, 3, 3, 4, 5, 6, 7, 10, 15, 0, 0 };
+ assertDistribution(16, 5, expected5);
+
+ const uint32_t expected6[] = {
+ 13, 13, 13, 13, 9, 11, 8, 9, 11, 14, 9, 11, 14, 14, 8, 10, 11, 14, 4, 5, 5, 6, 6, 7, 8, 10, 12, 15, 1, 1, 1, 1,
+ 6, 7, 8, 10, 12, 15, 2, 2, 2, 2, 12, 15, 3, 3, 3, 3, 4, 4, 4, 5, 5, 6, 7, 7, 9, 10, 12, 15, 0, 0, 0, 0 };
+ assertDistribution(16, 6, expected6);
+
+ const uint32_t expected7[] = {
+ 14, 14, 14, 13, 11, 14, 14, 10, 13, 14, 10, 12, 8, 8, 9, 10, 9, 10, 11, 12, 13, 15, 11, 12, 13, 13, 15, 8, 8, 9, 10, 11,
+ 11, 12, 13, 15, 4, 4, 5, 5, 5, 5, 15, 6, 6, 7, 7, 7, 8, 9, 9, 10, 11, 12, 14, 15, 1, 1, 1, 1, 1, 1, 1, 1,
+ 6, 6, 6, 7, 7, 8, 8, 9, 10, 11, 12, 13, 15, 2, 2, 2, 2, 2, 2, 2, 2, 12, 13, 15, 3, 3, 3, 3, 3, 3, 3, 3,
+ 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 9, 9, 10, 11, 12, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0 };
+ assertDistribution(16, 7, expected7);
+
+ const uint32_t expected8[] = {
+ 15, 14, 15, 15, 12, 14, 15, 12, 12, 11, 12, 13, 14, 13, 13, 13, 14, 15, 15, 9, 14, 9, 15, 10, 11, 11, 12, 8, 8, 8, 8, 9,
+ 9, 10, 10, 10, 11, 11, 12, 13, 13, 14, 10, 11, 11, 12, 13, 13, 14, 13, 13, 14, 15, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11,
+ 10, 10, 11, 11, 12, 13, 13, 14, 15, 4, 4, 4, 4, 15, 5, 5, 5, 5, 5, 5, 5, 15, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7,
+ 8, 8, 8, 9, 9, 9, 10, 10, 11, 11, 12, 12, 13, 14, 14, 15, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 11, 11, 12, 12, 13, 14, 14, 15, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 12, 12, 13, 14, 14, 15, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7,
+ 8, 8, 8, 9, 9, 9, 10, 10, 11, 11, 12, 12, 13, 14, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ assertDistribution(16, 8, expected8);
+
+ const uint32_t expected9[] = {
+ 15, 15, 15, 15, 14, 14, 15, 13, 13, 13, 13, 13, 14, 14, 15, 12, 14, 15, 15, 11, 11, 12, 13, 13, 13, 14, 14, 15, 15, 10, 12, 12,
+ 12, 13, 13, 13, 14, 14, 15, 15, 9, 9, 9, 10, 10, 11, 11, 11, 12, 12, 12, 12, 13, 13, 14, 15, 15, 8, 8, 8, 8, 9, 9, 9,
+ 9, 9, 9, 10, 9, 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 14, 14, 14, 10, 10, 10, 11, 11, 11, 12, 12, 12, 12,
+ 13, 13, 14, 14, 14, 15, 15, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11,
+ 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15, 4, 4, 4, 4, 4, 4, 4, 15, 15, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 14, 14, 14, 15, 15, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 13, 13, 13, 14, 14, 15, 15, 15,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9,
+ 9, 9, 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 12, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 13, 13, 13, 14, 14, 15, 15, 15,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ assertDistribution(16, 9, expected9);
+}
+
+void
+BucketDistributionTest::assertDistribution(uint32_t numColumns, uint32_t numBucketBits, const uint32_t expected[])
+{
+ BucketDistribution bd(numColumns, numBucketBits);
+ CPPUNIT_ASSERT_EQUAL(numColumns, bd.getNumColumns());
+ CPPUNIT_ASSERT_EQUAL((uint32_t)(1 << numBucketBits), bd.getNumBuckets());
+ for (uint32_t i = 0; i < bd.getNumBuckets(); ++i) {
+ CPPUNIT_ASSERT_EQUAL(expected[i],
+ bd.getColumn(document::BucketId(16, i)));
+ }
+}
+
+void BucketDistributionTest::testNumBucketBits()
+{
+ BucketDistribution bd(1, 4);
+ for (uint32_t i = 0; i <= 0xf; ++i) {
+ CPPUNIT_ASSERT_EQUAL(0u, bd.getColumn(document::BucketId(32, (rand() << 4) & i)));
+ }
+
+ bd.reset();
+ bd.setNumColumns(1);
+ bd.setNumBucketBits(8);
+ for (uint32_t i = 0; i <= 0xff; ++i) {
+ CPPUNIT_ASSERT_EQUAL(0u, bd.getColumn(document::BucketId(32, (rand() << 8) & i)));
+ }
+
+ bd.reset();
+ bd.setNumColumns(1);
+ bd.setNumBucketBits(16);
+ for (uint32_t i = 0; i <= 0xffff; ++i) {
+ CPPUNIT_ASSERT_EQUAL(0u, bd.getColumn(document::BucketId(32, (rand() << 16) & i)));
+ }
+}
diff --git a/vdslib/src/tests/container/.gitignore b/vdslib/src/tests/container/.gitignore
new file mode 100644
index 00000000000..583460ae288
--- /dev/null
+++ b/vdslib/src/tests/container/.gitignore
@@ -0,0 +1,3 @@
+*.So
+.depend
+Makefile
diff --git a/vdslib/src/tests/container/CMakeLists.txt b/vdslib/src/tests/container/CMakeLists.txt
new file mode 100644
index 00000000000..887fa69ad4b
--- /dev/null
+++ b/vdslib/src/tests/container/CMakeLists.txt
@@ -0,0 +1,12 @@
+# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_library(vdslib_containertest
+ SOURCES
+ documentlisttest.cpp
+ parameterstest.cpp
+ searchresulttest.cpp
+ documentsummarytest.cpp
+ smallvectortest.cpp
+ lruordertest.cpp
+ indexedcontaineriteratortest.cpp
+ DEPENDS
+)
diff --git a/vdslib/src/tests/container/documentlisttest.cpp b/vdslib/src/tests/container/documentlisttest.cpp
new file mode 100644
index 00000000000..60d01a63c1b
--- /dev/null
+++ b/vdslib/src/tests/container/documentlisttest.cpp
@@ -0,0 +1,538 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/fastos/fastos.h>
+#include <vespa/vdslib/container/writabledocumentlist.h>
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <vespa/document/base/testdocman.h>
+#include <vespa/document/config/config-documenttypes.h>
+#include <vespa/document/fieldvalue/document.h>
+#include <vespa/document/repo/documenttyperepo.h>
+#include <vespa/document/update/assignvalueupdate.h>
+#include <vespa/document/update/documentupdate.h>
+#include <vespa/vespalib/objects/nbostream.h>
+#include <vespa/vespalib/util/random.h>
+#include <vespa/vespalib/util/vstringfmt.h>
+#include <iostream>
+
+using document::DocumentTypeRepo;
+using document::readDocumenttypesConfig;
+using vespalib::nbostream;
+
+namespace vdslib {
+
+struct WritableDocumentListTest : public CppUnit::TestFixture {
+
+ void testSimple();
+ void testAlignedWriting();
+ void testSizeOf();
+ void testReadJavaFile();
+ void testGetSerializedSize();
+ void testCopyEntry();
+ void testOperationList();
+ void testSetTimestamp();
+ void testDifferentBuckets();
+
+ CPPUNIT_TEST_SUITE(WritableDocumentListTest);
+ CPPUNIT_TEST(testSimple);
+ CPPUNIT_TEST(testAlignedWriting);
+ CPPUNIT_TEST(testSizeOf);
+ CPPUNIT_TEST(testReadJavaFile);
+ CPPUNIT_TEST(testGetSerializedSize);
+ CPPUNIT_TEST(testCopyEntry);
+ CPPUNIT_TEST(testOperationList);
+ CPPUNIT_TEST(testSetTimestamp);
+ CPPUNIT_TEST(testDifferentBuckets);
+ CPPUNIT_TEST_SUITE_END();
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(WritableDocumentListTest);
+
+void WritableDocumentListTest::testDifferentBuckets()
+{
+ document::TestDocMan docman;
+ std::vector<char> buffer(1024);
+ WritableDocumentList block(docman.getTypeRepoSP(), &buffer[0], buffer.size());
+
+ std::unique_ptr<document::Document> doc1 = docman.createDocument("This is a test", "userdoc:test:1234:1");
+ block.addPut(*doc1);
+
+ std::unique_ptr<document::Document> doc2 = docman.createDocument("This is a test", "userdoc:test:4567:1");
+ try {
+ block.addPut(*doc2);
+ CPPUNIT_ASSERT(false);
+ } catch (...) {
+ }
+
+ block.addRemove(document::DocumentId("userdoc:test:1234:2"));
+
+ try {
+ block.addRemove(document::DocumentId("userdoc:test:4567:2"));
+ CPPUNIT_ASSERT(false);
+ } catch (...) {
+ }
+}
+
+void WritableDocumentListTest::testSimple()
+{
+ document::TestDocMan docman;
+ std::vector<char> buffer(1024);
+ std::vector<document::Document::SP > docs;
+ for (uint32_t i=1; i<10; ++i) {
+ docs.push_back(document::Document::SP(
+ docman.createDocument("This is a test",
+ vespalib::make_string("userdoc:test:123456789:%d", i)
+ ).release()));
+ }
+
+ WritableDocumentList block(docman.getTypeRepoSP(), &buffer[0], buffer.size());
+ // begin() should now equal start()
+ CPPUNIT_ASSERT(block.begin() == block.end());
+ // Add docs in the easy way.
+ block.addPut(*docs[0]);
+ block.addRemove(docs[1]->getId());
+ block.addPut(*docs[2], 0xfee1deadbabeb00bull);
+
+ // Add the way slotfile will.
+ WritableDocumentList::MetaEntry entry;
+ entry.timestamp = 1234;
+ entry.headerPos = 0;
+ nbostream stream;
+ docs[3]->serializeHeader(stream);
+ entry.headerLen = stream.size();
+ entry.bodyPos = entry.headerLen;
+ stream.clear();
+ docs[3]->serializeBody(stream);
+ entry.bodyLen = stream.size();
+ entry.flags = 0;
+
+ CPPUNIT_ASSERT(block.countFree() > entry.headerLen + entry.bodyLen
+ + sizeof(WritableDocumentList::MetaEntry));
+ char *pos = block.prepareMultiput(1, entry.headerLen + entry.bodyLen);
+ CPPUNIT_ASSERT(pos != 0);
+ document::ByteBuffer bb(pos, entry.headerLen + entry.bodyLen);
+ docs[3]->serializeHeader(bb);
+ docs[3]->serializeBody(bb);
+ std::vector<WritableDocumentList::MetaEntry> entries;
+ entries.push_back(entry);
+ block.commitMultiput(entries, pos);
+
+ // Copy buffer someplace else to simulate serialize/deserialize
+ std::vector<char> copy(buffer);
+
+ // Get documents out again. Verify correctness..
+ {
+ WritableDocumentList::const_iterator it = block.begin();
+ // First document putted
+ CPPUNIT_ASSERT(it->valid());
+ CPPUNIT_ASSERT(!it->isRemoveEntry());
+ CPPUNIT_ASSERT_EQUAL((uint64_t)0, it->getTimestamp());
+
+ std::unique_ptr<document::Document> doc(it->getDocument());
+ CPPUNIT_ASSERT(doc.get());
+
+ CPPUNIT_ASSERT_EQUAL(*docs[0], *doc);
+
+ CPPUNIT_ASSERT(++it != block.end());
+ // First document deleted
+ CPPUNIT_ASSERT(it->valid());
+ CPPUNIT_ASSERT(it->isRemoveEntry());
+ CPPUNIT_ASSERT_EQUAL((uint64_t)0, it->getTimestamp());
+
+ doc = it->getDocument();
+ CPPUNIT_ASSERT(doc.get());
+
+ CPPUNIT_ASSERT_EQUAL(docs[1]->getId(), doc->getId());
+ CPPUNIT_ASSERT(++it != block.end());
+ // Second document putted
+ CPPUNIT_ASSERT(it->valid());
+ CPPUNIT_ASSERT(!it->isRemoveEntry());
+ CPPUNIT_ASSERT_EQUAL((uint64_t)0xfee1deadbabeb00bull,
+ it->getTimestamp());
+ doc = it->getDocument();
+ CPPUNIT_ASSERT(doc.get());
+
+ CPPUNIT_ASSERT_EQUAL(*docs[2], *doc);
+ CPPUNIT_ASSERT(++it != block.end());
+ // Third document putted
+ CPPUNIT_ASSERT(it->valid());
+ CPPUNIT_ASSERT(!it->isRemoveEntry());
+ CPPUNIT_ASSERT_EQUAL((uint64_t)1234, it->getTimestamp());
+
+ doc = it->getDocument();
+ CPPUNIT_ASSERT(doc.get());
+
+ CPPUNIT_ASSERT_EQUAL(*docs[3], *doc);
+ CPPUNIT_ASSERT(++it == block.end());
+ }
+
+ // Test downsizing
+ CPPUNIT_ASSERT_EQUAL(621u, block.countFree());
+ uint32_t requiredSize = block.getBufferSize() - block.countFree();
+ std::vector<char> otherBuffer(requiredSize);
+ DocumentList otherBlock(block, &otherBuffer[0], otherBuffer.size());
+ CPPUNIT_ASSERT_EQUAL(403u, otherBlock.getBufferSize());
+ // Get documents out again of other block. Verify correctness..
+ {
+ DocumentList::const_iterator it = otherBlock.begin();
+ // First document putted
+ CPPUNIT_ASSERT(it->valid());
+ CPPUNIT_ASSERT(!it->isRemoveEntry());
+ CPPUNIT_ASSERT_EQUAL((uint64_t)0, it->getTimestamp());
+
+ std::unique_ptr<document::Document> doc(it->getDocument());
+ CPPUNIT_ASSERT(doc.get());
+
+ CPPUNIT_ASSERT_EQUAL(*docs[0], *doc);
+
+ CPPUNIT_ASSERT(++it != block.end());
+ // First document deleted
+ CPPUNIT_ASSERT(it->valid());
+ CPPUNIT_ASSERT(it->isRemoveEntry());
+ CPPUNIT_ASSERT_EQUAL((uint64_t)0, it->getTimestamp());
+
+ doc = it->getDocument();
+ CPPUNIT_ASSERT(doc.get());
+
+ CPPUNIT_ASSERT_EQUAL(docs[1]->getId(), doc->getId());
+ CPPUNIT_ASSERT(++it != block.end());
+ // Second document putted
+ CPPUNIT_ASSERT(it->valid());
+ CPPUNIT_ASSERT(!it->isRemoveEntry());
+ CPPUNIT_ASSERT_EQUAL((uint64_t)0xfee1deadbabeb00bull, it->getTimestamp());
+ doc = it->getDocument();
+ CPPUNIT_ASSERT(doc.get());
+ CPPUNIT_ASSERT_EQUAL(*docs[2], *doc);
+ CPPUNIT_ASSERT(++it != block.end());
+ // Third document putted
+ CPPUNIT_ASSERT(it->valid());
+ CPPUNIT_ASSERT(!it->isRemoveEntry());
+ CPPUNIT_ASSERT_EQUAL((uint64_t)1234, it->getTimestamp());
+
+ doc = it->getDocument();
+ CPPUNIT_ASSERT(doc.get());
+ CPPUNIT_ASSERT_EQUAL(*docs[3], *doc);
+ CPPUNIT_ASSERT(++it == block.end());
+ }
+
+ // begin() should equal start() after clear
+ block.clear();
+ CPPUNIT_ASSERT(block.begin() == block.end());
+}
+
+void WritableDocumentListTest::testSetTimestamp()
+{
+ document::TestDocMan docman;
+ std::vector<char> buffer(1024);
+
+ WritableDocumentList block(docman.getTypeRepoSP(), &buffer[0], buffer.size());
+ // begin() should now equal start()
+ CPPUNIT_ASSERT(block.begin() == block.end());
+ // Add docs in the easy way.
+ std::unique_ptr<document::Document> doc(
+ docman.createDocument("This is a test",
+ vespalib::make_string("userdoc:test:123456789:t")));
+
+ block.addPut(*doc);
+
+ CPPUNIT_ASSERT(block.begin() != block.end());
+
+ block.begin()->setTimestamp(1234);
+
+ CPPUNIT_ASSERT_EQUAL((Timestamp)1234, block.begin()->getTimestamp());
+}
+
+void WritableDocumentListTest::testAlignedWriting()
+{
+ document::TestDocMan docman;
+ vespalib::RandomGen randomizer(5123);
+ std::vector<char> buffer(1024*1024);
+
+ std::vector<document::Document::SP > docs;
+ for (uint32_t i=1; i<10; ++i) {
+ docs.push_back(document::Document::SP(
+ docman.createDocument("Aligned writing test blaaaah",
+ vespalib::make_string("userdoc:test:123456789:%d", i)
+ ).release()));
+ }
+
+ WritableDocumentList block(docman.getTypeRepoSP(), &buffer[0], buffer.size());
+
+ // Add documents aligned the way slotfile will.
+ for (uint32_t i=1; i<50; ++i) {
+ std::vector<WritableDocumentList::MetaEntry> entries;
+ uint32_t currentPos = 0;
+ for (uint32_t j=0, n=randomizer.nextUint32(1,10); j<n; ++j) {
+ WritableDocumentList::MetaEntry entry;
+ entry.timestamp = i * 1000 + j;
+ entry.headerPos = currentPos;
+ entry.headerLen = randomizer.nextUint32(5, 50);
+ entry.bodyPos = currentPos + entry.headerLen;
+ entry.bodyLen = randomizer.nextUint32(0, 4000);
+ entry.flags = 0;
+ currentPos += entry.headerLen + entry.bodyLen;
+ entries.push_back(entry);
+ }
+ currentPos += 512 - (currentPos % 512);
+ CPPUNIT_ASSERT(currentPos % 512 == 0);
+
+ CPPUNIT_ASSERT(block.countFree() > currentPos + entries.size()
+ * sizeof(WritableDocumentList::MetaEntry));
+ char *pos = block.prepareMultiput(entries.size(), currentPos);
+ CPPUNIT_ASSERT(pos != 0);
+ CPPUNIT_ASSERT((pos - &buffer[0]) % 512 == 0);
+ block.commitMultiput(entries, pos);
+ }
+}
+
+void WritableDocumentListTest::testSizeOf()
+{
+ CPPUNIT_ASSERT_EQUAL(size_t(32), sizeof(WritableDocumentList::MetaEntry));
+
+ std::string buffercont("This is a buffer of data we will create meta "
+ " entry from to verify binary compability");
+ std::vector<char> buffer(buffercont.begin(), buffercont.end());
+ CPPUNIT_ASSERT(buffer.size() > sizeof(WritableDocumentList::MetaEntry));
+
+ WritableDocumentList::MetaEntry* e(reinterpret_cast<WritableDocumentList::MetaEntry*>(&buffer[0]));
+
+ CPPUNIT_ASSERT_EQUAL(Timestamp(2338328219631577172ull), e->timestamp);
+ CPPUNIT_ASSERT_EQUAL(uint32_t(1969365089), e->headerPos);
+ CPPUNIT_ASSERT_EQUAL(uint32_t(1919247974), e->headerLen);
+ CPPUNIT_ASSERT_EQUAL(uint32_t(543584032), e->bodyPos);
+ CPPUNIT_ASSERT_EQUAL(uint32_t(1635017060), e->bodyLen);
+ CPPUNIT_ASSERT_EQUAL(uint32_t(32), uint32_t(e->flags));
+}
+
+void WritableDocumentListTest::testReadJavaFile()
+{
+ DocumentTypeRepo::SP repo(new DocumentTypeRepo(readDocumenttypesConfig(
+ "../test/files/documenttypes.cfg")));
+
+ //read file
+ int file = open("../test/files/documentlist-java.dat", O_RDONLY);
+ if (file == -1) {
+ CPPUNIT_ASSERT(0);
+ }
+
+ uint32_t len = lseek(file, 0, SEEK_END);
+ lseek(file, 0, SEEK_SET);
+
+ vespalib::MallocPtr data(len);
+ CPPUNIT_ASSERT_EQUAL((ssize_t) len, read(file, data, len));
+ close(file);
+
+
+ //create documentlist
+ DocumentList block(repo, data.str(), len, true);
+
+ CPPUNIT_ASSERT_EQUAL((uint32_t) 4, block.size());
+
+ DocumentList::const_iterator it = block.begin();
+ CPPUNIT_ASSERT(it->valid());
+ CPPUNIT_ASSERT(!it->isRemoveEntry());
+ CPPUNIT_ASSERT(!it->isBodyStripped());
+ CPPUNIT_ASSERT(!it->isUpdateEntry());
+ CPPUNIT_ASSERT_EQUAL((uint64_t)0, it->getTimestamp());
+ std::unique_ptr<document::Document> doc(it->getDocument());
+ CPPUNIT_ASSERT(doc.get());
+ CPPUNIT_ASSERT_EQUAL(document::DocumentId("userdoc:foo:99999999:1"),
+ doc->getId());
+ vespalib::string foo = "foo";
+ CPPUNIT_ASSERT_EQUAL(foo, doc->getValue("headerstring")->getAsString());
+
+ CPPUNIT_ASSERT(++it != block.end());
+
+ CPPUNIT_ASSERT(it->valid());
+ CPPUNIT_ASSERT(it->isRemoveEntry());
+ CPPUNIT_ASSERT(!it->isBodyStripped());
+ CPPUNIT_ASSERT(!it->isUpdateEntry());
+ CPPUNIT_ASSERT_EQUAL((uint64_t)0, it->getTimestamp());
+ doc = it->getDocument();
+ CPPUNIT_ASSERT(doc.get());
+ CPPUNIT_ASSERT_EQUAL(document::DocumentId("userdoc:foo:99999999:2"),
+ doc->getId());
+
+ CPPUNIT_ASSERT(++it != block.end());
+
+ CPPUNIT_ASSERT(it->valid());
+ CPPUNIT_ASSERT(!it->isRemoveEntry());
+ CPPUNIT_ASSERT(!it->isBodyStripped());
+ CPPUNIT_ASSERT(!it->isUpdateEntry());
+ CPPUNIT_ASSERT_EQUAL((uint64_t)0, it->getTimestamp());
+ doc = it->getDocument();
+ CPPUNIT_ASSERT(doc.get());
+ CPPUNIT_ASSERT_EQUAL(document::DocumentId("userdoc:foo:99999999:3"),
+ doc->getId());
+ CPPUNIT_ASSERT_EQUAL(5.5f, doc->getValue("bodyfloat")->getAsFloat());
+
+ CPPUNIT_ASSERT(++it != block.end());
+
+ CPPUNIT_ASSERT(it->valid());
+ CPPUNIT_ASSERT(!it->isRemoveEntry());
+ CPPUNIT_ASSERT(!it->isBodyStripped());
+ CPPUNIT_ASSERT(it->isUpdateEntry());
+ CPPUNIT_ASSERT_EQUAL((uint64_t)0, it->getTimestamp());
+ document::DocumentUpdate::UP docUp = it->getUpdate();
+ CPPUNIT_ASSERT(docUp.get());
+ const document::AssignValueUpdate* valUp = dynamic_cast<const document::AssignValueUpdate*>(docUp->getUpdates().front().getUpdates().front().get());
+ vespalib::string ballooooo = "ballooooo";
+ CPPUNIT_ASSERT_EQUAL(ballooooo, valUp->getValue().getAsString());
+
+ CPPUNIT_ASSERT(++it == block.end());
+}
+
+void WritableDocumentListTest::testGetSerializedSize() {
+ document::TestDocMan docman;
+ std::vector<char> buffer(1024);
+ std::vector<document::Document::SP > docs;
+ for (uint32_t i=1; i<3; ++i) {
+ docs.push_back(document::Document::SP(
+ docman.createDocument("This is a test, blah bloh bluh blih",
+ vespalib::make_string("userdoc:test:1298798789:%d", i)
+ ).release()));
+ }
+ WritableDocumentList block(docman.getTypeRepoSP(), &buffer[0], buffer.size());
+ // begin() should now equal start()
+ CPPUNIT_ASSERT(block.begin() == block.end());
+ // Add docs in the easy way.
+ block.addPut(*docs[0]);
+ block.addRemove(docs[1]->getId());
+
+ WritableDocumentList::const_iterator it = block.begin();
+ CPPUNIT_ASSERT_EQUAL((const uint32_t)(docs[0]->serialize()->getLength()
+ + sizeof(DocumentList::MetaEntry)),
+ it->getSerializedSize());
+}
+
+void WritableDocumentListTest::testCopyEntry() {
+ DocumentTypeRepo::SP repo(new DocumentTypeRepo(readDocumenttypesConfig(
+ "../test/files/documenttypes.cfg")));
+
+ //read file
+ int file = open("../test/files/documentlist-java.dat", O_RDONLY);
+ if (file == -1) {
+ CPPUNIT_ASSERT(0);
+ }
+
+ uint32_t len = lseek(file, 0, SEEK_END);
+ lseek(file, 0, SEEK_SET);
+
+ vespalib::MallocPtr data(len);
+ CPPUNIT_ASSERT_EQUAL((ssize_t) len, read(file, data, len));
+ close(file);
+
+
+ //create documentlist
+ DocumentList block(repo, data.str(), len, true);
+
+ CPPUNIT_ASSERT_EQUAL((uint32_t) 4, block.size());
+
+ //create a writabledocumentlist
+ std::vector<char> buffer(1024);
+ WritableDocumentList wrBlock(repo, &buffer[0], buffer.size());
+
+ DocumentList::const_iterator it = block.begin();
+ wrBlock.addEntry(*it);
+ CPPUNIT_ASSERT_EQUAL((uint32_t) 1, wrBlock.size());
+
+ ++it;
+ wrBlock.addEntry(*it);
+ CPPUNIT_ASSERT_EQUAL((uint32_t) 2, wrBlock.size());
+
+ ++it;
+ wrBlock.addEntry(*it);
+ CPPUNIT_ASSERT_EQUAL((uint32_t) 3, wrBlock.size());
+
+ ++it;
+ wrBlock.addEntry(*it);
+ CPPUNIT_ASSERT_EQUAL((uint32_t) 4, wrBlock.size());
+
+
+ it = block.begin();
+ DocumentList::const_iterator wrIt = wrBlock.begin();
+
+ //test equality of first entry
+ CPPUNIT_ASSERT_EQUAL(it->getFlags(), wrIt->getFlags());
+ std::unique_ptr<document::Document> doc(it->getDocument());
+ CPPUNIT_ASSERT(doc.get());
+
+ std::unique_ptr<document::Document> wrDoc(wrIt->getDocument());
+ CPPUNIT_ASSERT(wrDoc.get());
+ CPPUNIT_ASSERT_EQUAL(*doc, *wrDoc);
+
+ ++it;
+ ++wrIt;
+
+ //test equality of second entry
+ CPPUNIT_ASSERT_EQUAL(it->getFlags(), wrIt->getFlags());
+ doc = it->getDocument();
+ CPPUNIT_ASSERT(doc.get());
+
+ wrDoc = wrIt->getDocument();
+ CPPUNIT_ASSERT(wrDoc.get());
+ CPPUNIT_ASSERT_EQUAL(*doc, *wrDoc);
+
+ ++it;
+ ++wrIt;
+
+ //test equality of third entry
+ CPPUNIT_ASSERT_EQUAL(it->getFlags(), wrIt->getFlags());
+ doc = it->getDocument();
+ CPPUNIT_ASSERT(doc.get());
+
+ wrDoc = wrIt->getDocument();
+ CPPUNIT_ASSERT(wrDoc.get());
+ CPPUNIT_ASSERT_EQUAL(*doc, *wrDoc);
+
+ ++it;
+ ++wrIt;
+
+ //test equality of fourth entry
+ CPPUNIT_ASSERT_EQUAL(it->getFlags(), wrIt->getFlags());
+ document::DocumentUpdate::UP docUp = it->getUpdate();
+ CPPUNIT_ASSERT(docUp.get());
+
+ document::DocumentUpdate::UP wrDocUp = wrIt->getUpdate();
+ CPPUNIT_ASSERT(wrDocUp.get());
+ CPPUNIT_ASSERT_EQUAL(docUp->getId(), wrDocUp->getId());
+}
+
+void WritableDocumentListTest::testOperationList()
+{
+ document::TestDocMan docman;
+ OperationList ol;
+ for (uint32_t i=0; i<3000; ++i) {
+ ol.addPut(docman.createDocument(
+ "This is a test, blah bloh bluh blih",
+ vespalib::make_string("userdoc:test:1298798789:%d", i)));
+ }
+
+ for (uint32_t i=5000; i<5900; ++i) {
+ ol.addRemove(document::DocumentId(
+ vespalib::make_string("userdoc:test:1298798789:%d", i)));
+ }
+
+ std::vector<char> buf(ol.getRequiredBufferSize());
+
+ MutableDocumentList mdl(docman.getTypeRepoSP(), &(buf[0]), buf.size());
+ mdl.addOperationList(ol);
+
+ DocumentList::const_iterator it = mdl.begin();
+
+ for (uint32_t i=0; i<3000; ++i, it++) {
+ CPPUNIT_ASSERT_EQUAL(
+ vespalib::make_vespa_string("userdoc:test:1298798789:%d", i),
+ it->getDocument()->getId().toString());
+ CPPUNIT_ASSERT(!it->isRemoveEntry());
+ }
+
+ for (uint32_t i=5000; i<5900; ++i, it++) {
+ CPPUNIT_ASSERT_EQUAL(
+ vespalib::make_vespa_string("userdoc:test:1298798789:%d", i),
+ it->getDocument()->getId().toString());
+ CPPUNIT_ASSERT(it->isRemoveEntry());
+ }
+}
+
+}
diff --git a/vdslib/src/tests/container/documentsummarytest.cpp b/vdslib/src/tests/container/documentsummarytest.cpp
new file mode 100644
index 00000000000..80547e28d1f
--- /dev/null
+++ b/vdslib/src/tests/container/documentsummarytest.cpp
@@ -0,0 +1,53 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/fastos/fastos.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <vespa/document/base/testdocman.h>
+#include <vespa/vdslib/container/documentsummary.h>
+
+namespace vdslib {
+
+struct DocumentSummaryTest : public CppUnit::TestFixture {
+
+ void testSimple();
+
+ CPPUNIT_TEST_SUITE(DocumentSummaryTest);
+ CPPUNIT_TEST(testSimple);
+ CPPUNIT_TEST_SUITE_END();
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(DocumentSummaryTest);
+
+void DocumentSummaryTest::testSimple()
+{
+ DocumentSummary a;
+ CPPUNIT_ASSERT(a.getSummaryCount() == 0);
+ a.addSummary("doc1", "summary1", 8);
+ CPPUNIT_ASSERT(a.getSummaryCount() == 1);
+ a.addSummary("aoc12", "summary17", 9);
+ CPPUNIT_ASSERT(a.getSummaryCount() == 2);
+
+ size_t r;
+ const char * docId;
+ const void * buf(NULL);
+ a.getSummary(0, docId, buf, r);
+ CPPUNIT_ASSERT(r == 8);
+ CPPUNIT_ASSERT(strcmp(docId, "doc1") == 0);
+ CPPUNIT_ASSERT(memcmp(buf, "summary1", r) == 0);
+ a.getSummary(1, docId, buf, r);
+ CPPUNIT_ASSERT(r == 9);
+ CPPUNIT_ASSERT(strcmp(docId, "aoc12") == 0);
+ CPPUNIT_ASSERT(memcmp(buf, "summary17", r) == 0);
+
+ a.sort();
+ a.getSummary(0, docId, buf, r);
+ CPPUNIT_ASSERT(r == 9);
+ CPPUNIT_ASSERT(strcmp(docId, "aoc12") == 0);
+ CPPUNIT_ASSERT(memcmp(buf, "summary17", r) == 0);
+ a.getSummary(1, docId, buf, r);
+ CPPUNIT_ASSERT(r == 8);
+ CPPUNIT_ASSERT(strcmp(docId, "doc1") == 0);
+ CPPUNIT_ASSERT(memcmp(buf, "summary1", r) == 0);
+}
+
+}
diff --git a/vdslib/src/tests/container/indexedcontaineriteratortest.cpp b/vdslib/src/tests/container/indexedcontaineriteratortest.cpp
new file mode 100644
index 00000000000..a7697116a15
--- /dev/null
+++ b/vdslib/src/tests/container/indexedcontaineriteratortest.cpp
@@ -0,0 +1,61 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <vespa/vdslib/container/smallvector.h>
+#include <sys/time.h>
+
+namespace storage {
+namespace lib {
+
+struct IndexedContainerIteratorTest : public CppUnit::TestFixture {
+
+ void testNormalUsage();
+ void testSorting();
+
+ CPPUNIT_TEST_SUITE(IndexedContainerIteratorTest);
+ CPPUNIT_TEST(testNormalUsage);
+ CPPUNIT_TEST(testSorting);
+ CPPUNIT_TEST_SUITE_END();
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(IndexedContainerIteratorTest);
+
+void
+IndexedContainerIteratorTest::testNormalUsage()
+{
+ typedef IndexedContainerIterator<std::vector<int>, int> Iterator;
+ {
+ std::vector<int> v;
+ Iterator begin = Iterator(v, 0);
+ Iterator end = Iterator(v, 0);
+ CPPUNIT_ASSERT_EQUAL(begin, Iterator(v, 0));
+ CPPUNIT_ASSERT_EQUAL(end, Iterator(v, 0));
+ CPPUNIT_ASSERT(begin == end);
+ }
+ {
+ std::vector<int> v;
+ v.push_back(5);
+ Iterator begin = Iterator(v, 0);
+ Iterator end = Iterator(v, 1);
+ CPPUNIT_ASSERT_EQUAL(begin, Iterator(v, 0));
+ CPPUNIT_ASSERT_EQUAL(end, Iterator(v, 1));
+ CPPUNIT_ASSERT(begin != end);
+ }
+}
+
+void
+IndexedContainerIteratorTest::testSorting()
+{
+ typedef IndexedContainerIterator<std::vector<int>, int> Iterator;
+ std::vector<int> v;
+ v.push_back(5);
+ v.push_back(9);
+ v.push_back(2);
+ std::sort(Iterator(v, 0), Iterator(v, 3));
+ CPPUNIT_ASSERT_EQUAL(2, v[0]);
+ CPPUNIT_ASSERT_EQUAL(5, v[1]);
+ CPPUNIT_ASSERT_EQUAL(9, v[2]);
+}
+
+} // lib
+} // storage
diff --git a/vdslib/src/tests/container/lruordertest.cpp b/vdslib/src/tests/container/lruordertest.cpp
new file mode 100644
index 00000000000..57e990dee29
--- /dev/null
+++ b/vdslib/src/tests/container/lruordertest.cpp
@@ -0,0 +1,109 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/vdslib/container/lruorder.h>
+#include <vespa/vdstestlib/cppunit/macros.h>
+
+namespace storage {
+namespace lib {
+
+struct LruOrderTest : public CppUnit::TestFixture {
+
+ void testSimple();
+
+ CPPUNIT_TEST_SUITE(LruOrderTest);
+ CPPUNIT_TEST(testSimple);
+ CPPUNIT_TEST_SUITE_END();
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(LruOrderTest);
+
+namespace {
+
+ struct LruMap {
+ struct Entry {
+ std::string _value;
+ LruOrder<int, LruMap>::EntryRef _order;
+ };
+ std::map<int, Entry> _map;
+ LruOrder<int, LruMap> _order;
+
+ LruMap(uint32_t size) : _order(size, *this) {}
+
+ void removedFromOrder(int i) {
+ _map.erase(i);
+ }
+
+ std::string& operator[](int i) {
+ std::map<int, Entry>::iterator it(_map.find(i));
+ if (it == _map.end()) {
+ Entry e;
+ e._order = _order.add(i);
+ _map[i] = e;
+ return _map[i]._value;
+ } else {
+ _order.moveToStart(it->second._order);
+ return it->second._value;
+ }
+ }
+
+ void remove(int i) {
+ std::map<int, Entry>::iterator it(_map.find(i));
+ if (it != _map.end()) {
+ _order.remove(it->second._order);
+ }
+ }
+
+ void clear() {
+ _map.clear();
+ _order.clear();
+ }
+ };
+
+}
+
+void
+LruOrderTest::testSimple()
+{
+ LruMap map(3);
+ CPPUNIT_ASSERT_EQUAL(std::string("[]"), map._order.toString());
+
+ map[3] = "1";
+ CPPUNIT_ASSERT_EQUAL(std::string("[3]"), map._order.toString());
+
+ map[7] = "2";
+ CPPUNIT_ASSERT_EQUAL(std::string("[7, 3]"), map._order.toString());
+
+ map[9] = "3";
+ CPPUNIT_ASSERT_EQUAL(std::string("[9, 7, 3]"), map._order.toString());
+
+ map[13] = "4";
+ CPPUNIT_ASSERT_EQUAL(std::string("[13, 9, 7]"), map._order.toString());
+
+ map[9];
+ CPPUNIT_ASSERT_EQUAL(std::string("[9, 13, 7]"), map._order.toString());
+
+ map.remove(13);
+ CPPUNIT_ASSERT_EQUAL(std::string("[9, 7]"), map._order.toString());
+
+ map.clear();
+ CPPUNIT_ASSERT_EQUAL(std::string("[]"), map._order.toString());
+
+ map[4] = "3";
+ CPPUNIT_ASSERT_EQUAL(std::string("[4]"), map._order.toString());
+
+ map[2] = "4";
+ CPPUNIT_ASSERT_EQUAL(std::string("[2, 4]"), map._order.toString());
+
+ map[4] = "4";
+ CPPUNIT_ASSERT_EQUAL(std::string("[4, 2]"), map._order.toString());
+
+ map[7] = "4";
+ CPPUNIT_ASSERT_EQUAL(std::string("[7, 4, 2]"), map._order.toString());
+
+ map[8] = "4";
+ CPPUNIT_ASSERT_EQUAL(std::string("[8, 7, 4]"), map._order.toString());
+}
+
+
+} // lib
+} // storage
diff --git a/vdslib/src/tests/container/parameterstest.cpp b/vdslib/src/tests/container/parameterstest.cpp
new file mode 100644
index 00000000000..63ab18bcd26
--- /dev/null
+++ b/vdslib/src/tests/container/parameterstest.cpp
@@ -0,0 +1,53 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/fastos/fastos.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <vespa/document/repo/documenttyperepo.h>
+#include <vespa/vdslib/container/parameters.h>
+
+using document::DocumentTypeRepo;
+using namespace vdslib;
+
+class Parameters_Test : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(Parameters_Test);
+ CPPUNIT_TEST(testParameters);
+ CPPUNIT_TEST_SUITE_END();
+
+protected:
+ void testParameters();
+};
+
+#ifndef FASTOS_NO_THREADS
+CPPUNIT_TEST_SUITE_REGISTRATION(Parameters_Test);
+#endif
+
+void
+Parameters_Test::testParameters()
+{
+ Parameters par;
+ par.set("fast", "overture");
+ par.set("overture", "yahoo");
+ par.set("number", 6);
+ par.set("long", 8589934590L);
+ par.set("double", 0.25);
+ std::unique_ptr<document::ByteBuffer> buffer(par.serialize());
+
+ buffer->flip();
+ DocumentTypeRepo repo;
+ Parameters par2(repo, *buffer);
+
+ CPPUNIT_ASSERT_EQUAL(vespalib::stringref("overture"), par2.get("fast"));
+ CPPUNIT_ASSERT_EQUAL(vespalib::stringref("yahoo"), par2.get("overture"));
+ std::string stringDefault = "wayne corp";
+ int numberDefault = 123;
+ long longDefault = 456;
+ double doubleDefault = 0.5;
+ CPPUNIT_ASSERT_EQUAL(6, par2.get("number", numberDefault));
+ CPPUNIT_ASSERT_EQUAL(8589934590L, par2.get("long", longDefault));
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(0.25, par2.get("double", doubleDefault), 0.0001);
+
+ CPPUNIT_ASSERT_EQUAL(stringDefault, par2.get("nonexistingstring", stringDefault));
+ CPPUNIT_ASSERT_EQUAL(numberDefault, par2.get("nonexistingnumber", numberDefault));
+ CPPUNIT_ASSERT_EQUAL(longDefault, par2.get("nonexistinglong", longDefault));
+ CPPUNIT_ASSERT_EQUAL(doubleDefault, par2.get("nonexistingdouble", doubleDefault));
+}
diff --git a/vdslib/src/tests/container/searchresulttest.cpp b/vdslib/src/tests/container/searchresulttest.cpp
new file mode 100644
index 00000000000..b72df61c2dd
--- /dev/null
+++ b/vdslib/src/tests/container/searchresulttest.cpp
@@ -0,0 +1,85 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/fastos/fastos.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <vespa/document/base/testdocman.h>
+#include <vespa/vdslib/container/searchresult.h>
+
+namespace vdslib {
+
+struct SearchResultTest : public CppUnit::TestFixture {
+
+ void testSimple();
+ void testSimpleSortData();
+
+ CPPUNIT_TEST_SUITE(SearchResultTest);
+ CPPUNIT_TEST(testSimple);
+ CPPUNIT_TEST(testSimpleSortData);
+ CPPUNIT_TEST_SUITE_END();
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(SearchResultTest);
+
+void SearchResultTest::testSimple()
+{
+ SearchResult a;
+ CPPUNIT_ASSERT(a.getHitCount() == 0);
+ a.addHit(7, "doc1", 6);
+ CPPUNIT_ASSERT(a.getHitCount() == 1);
+ a.addHit(8, "doc2", 7);
+ CPPUNIT_ASSERT(a.getHitCount() == 2);
+ const char *docId;
+ SearchResult::RankType r;
+ CPPUNIT_ASSERT_EQUAL(a.getHit(0, docId, r), 7ul);
+ CPPUNIT_ASSERT(strcmp(docId, "doc1") == 0);
+ CPPUNIT_ASSERT(r == 6);
+ CPPUNIT_ASSERT_EQUAL(a.getHit(1, docId, r), 8ul);
+ CPPUNIT_ASSERT(strcmp(docId, "doc2") == 0);
+ CPPUNIT_ASSERT(r == 7);
+ a.sort();
+ CPPUNIT_ASSERT_EQUAL(a.getHit(0, docId, r), 8ul);
+ CPPUNIT_ASSERT(strcmp(docId, "doc2") == 0);
+ CPPUNIT_ASSERT(r == 7);
+ CPPUNIT_ASSERT_EQUAL(a.getHit(1, docId, r), 7ul);
+ CPPUNIT_ASSERT(strcmp(docId, "doc1") == 0);
+ CPPUNIT_ASSERT(r == 6);
+}
+
+void SearchResultTest::testSimpleSortData()
+{
+ SearchResult a;
+ CPPUNIT_ASSERT(a.getHitCount() == 0);
+ a.addHit(7, "doc1", 6, "abce", 4);
+ CPPUNIT_ASSERT(a.getHitCount() == 1);
+ a.addHit(8, "doc2", 7, "abcde", 5);
+ CPPUNIT_ASSERT(a.getHitCount() == 2);
+ const char *docId;
+ SearchResult::RankType r;
+ CPPUNIT_ASSERT_EQUAL(a.getHit(0, docId, r), 7ul);
+ CPPUNIT_ASSERT(strcmp(docId, "doc1") == 0);
+ CPPUNIT_ASSERT(r == 6);
+ const void *buf;
+ size_t sz;
+ a.getSortBlob(0, buf, sz);
+ CPPUNIT_ASSERT(sz == 4);
+ CPPUNIT_ASSERT(memcmp("abce", buf, sz) == 0);
+ CPPUNIT_ASSERT_EQUAL(a.getHit(1, docId, r), 8ul);
+ CPPUNIT_ASSERT(strcmp(docId, "doc2") == 0);
+ CPPUNIT_ASSERT(r == 7);
+ a.getSortBlob(1, buf, sz);
+ CPPUNIT_ASSERT(sz == 5);
+ CPPUNIT_ASSERT(memcmp("abcde", buf, sz) == 0);
+ a.sort();
+ CPPUNIT_ASSERT_EQUAL(a.getHit(0, docId, r), 8ul);
+ CPPUNIT_ASSERT(strcmp(docId, "doc2") == 0);
+ CPPUNIT_ASSERT(r == 7);
+ a.getSortBlob(0, buf, sz);
+ CPPUNIT_ASSERT(sz == 5);
+ CPPUNIT_ASSERT_EQUAL(a.getHit(1, docId, r), 7ul);
+ CPPUNIT_ASSERT(strcmp(docId, "doc1") == 0);
+ CPPUNIT_ASSERT(r == 6);
+ a.getSortBlob(1, buf, sz);
+ CPPUNIT_ASSERT(sz == 4);
+}
+
+}
diff --git a/vdslib/src/tests/container/smallvectortest.cpp b/vdslib/src/tests/container/smallvectortest.cpp
new file mode 100644
index 00000000000..ac046f80caa
--- /dev/null
+++ b/vdslib/src/tests/container/smallvectortest.cpp
@@ -0,0 +1,274 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <vespa/vdslib/container/smallvector.h>
+#include <sys/time.h>
+
+namespace storage {
+namespace lib {
+
+struct SmallVectorTest : public CppUnit::TestFixture {
+
+ void testNormalUsage();
+ void testPerformance();
+ void testSwapVectorContents();
+ void testErase();
+ void testCopy();
+
+ CPPUNIT_TEST_SUITE(SmallVectorTest);
+ CPPUNIT_TEST(testNormalUsage);
+ CPPUNIT_TEST(testPerformance);
+ CPPUNIT_TEST(testSwapVectorContents);
+ CPPUNIT_TEST(testErase);
+ CPPUNIT_TEST(testCopy);
+ CPPUNIT_TEST_SUITE_END();
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(SmallVectorTest);
+
+namespace {
+ template<typename T>
+ inline std::ostream& operator<<(std::ostream& out,
+ const std::vector<T>& v)
+ {
+ out << "[";
+ for (size_t i=0; i<v.size(); ++i) {
+ out << "\n " << v[i];
+ }
+ if (!v.empty()) out << "\n";
+ out << "]";
+ return out;
+ }
+
+ template<typename T, size_t S>
+ void assertEqual(const SmallVector<T, S>& sv, const std::vector<T>& v) {
+ if (!(sv == v)) {
+ std::ostringstream ost;
+ ost << "Small vector " << sv << " is not equal to vector " << v;
+ CPPUNIT_FAIL(ost.str());
+ }
+ }
+}
+
+void
+SmallVectorTest::testNormalUsage()
+{
+ std::vector<uint16_t> expected;
+ SmallVector<uint16_t, 8> actual;
+ for (uint16_t i=0; i<16; ++i) {
+ expected.push_back(i);
+ actual.push_back(i);
+ assertEqual(actual, expected);
+ }
+
+ SmallVector<uint16_t, 8> copy(actual);
+ SmallVector<uint16_t, 16> copy2(actual);
+}
+
+namespace {
+
+ uint64_t getCurrentTimeInMicros() {
+ struct timeval mytime;
+ gettimeofday(&mytime, 0);
+ return mytime.tv_sec * 1000000llu + mytime.tv_usec;
+ }
+
+ template<typename IntContainer>
+ struct PerformanceTestClass {
+ uint32_t count;
+
+ PerformanceTestClass(int c) : count(c) {}
+
+ IntContainer getContainer(int minVal) {
+ IntContainer result;
+ for (uint32_t i=0; i<count; ++i) {
+ result.push_back(minVal + i);
+ }
+ return result;
+ }
+ };
+
+ template<typename IntContainer>
+ uint64_t getPerformance(int containerSize) {
+ uint64_t start = getCurrentTimeInMicros();
+ int value = 0;
+ PerformanceTestClass<IntContainer> foo(containerSize);
+ for (uint32_t i=0, n=10 * 1024; i<n; ++i) {
+ IntContainer ic(foo.getContainer(start));
+ value += ic[0] + ic[1] - ic[2];
+ }
+ uint64_t stop = getCurrentTimeInMicros();
+ return (stop - start);
+ }
+
+ struct ArgumentTestClass {
+ uint32_t count;
+
+ ArgumentTestClass(int c) : count(c) {}
+
+ void getContainer(int minVal, std::vector<int>& result) {
+ for (uint32_t i=0; i<count; ++i) {
+ result.push_back(minVal + i);
+ }
+ }
+ };
+
+ uint64_t getPerformance2(int containerSize) {
+ uint64_t start = getCurrentTimeInMicros();
+ int value = 0;
+ ArgumentTestClass foo(containerSize);
+ for (uint32_t i=0, n=10 * 1024; i<n; ++i) {
+ std::vector<int> ic;
+ foo.getContainer(start, ic);
+ value += ic[0] + ic[1] - ic[2];
+ }
+ uint64_t stop = getCurrentTimeInMicros();
+ return (stop - start);
+ }
+}
+
+void
+SmallVectorTest::testPerformance()
+{
+ size_t low = 3;
+ size_t high = 16;
+ SmallVector<int> sv;
+
+ CPPUNIT_ASSERT(low <= sv.getEfficientSizeLimit());
+ CPPUNIT_ASSERT(high > sv.getEfficientSizeLimit());
+
+ uint64_t vectorTime1 = getPerformance<std::vector<int> >(low);
+ uint64_t smallVectorTime1 = getPerformance<SmallVector<int> >(low);
+ uint64_t asArgTime1 = getPerformance2(low);
+
+ uint64_t vectorTime2 = getPerformance<std::vector<int> >(high);
+ uint64_t smallVectorTime2 = getPerformance<SmallVector<int> >(high);
+ uint64_t asArgTime2 = getPerformance2(high);
+
+ double factor1 = static_cast<double>(vectorTime1) / smallVectorTime1;
+ double factor2 = static_cast<double>(vectorTime2) / smallVectorTime2;
+
+ double factor3 = static_cast<double>(asArgTime1) / smallVectorTime1;
+ double factor4 = static_cast<double>(asArgTime2) / smallVectorTime2;
+
+ std::cerr << "\n"
+ << " Small vector is " << factor1
+ << " x faster than std::vector with few elements\n"
+ << " Small vector is " << factor2
+ << " x faster than std::vector with many elements\n"
+ << " Small vector is " << factor3
+ << " x faster than std::vector as arg with few elements\n"
+ << " Small vector is " << factor4
+ << " x faster than std::vector as arg with many elements\n";
+
+ // At time of test writing, vector is ~43 times faster with small data, and
+ // ~0.9 times as fast on bigger. (Without vespa malloc)
+ // With vespa malloc it is about ~14 times faster.
+
+ /* Cannot run on factory as too much other runs in parallel.
+ CPPUNIT_ASSERT(factor1 > 25);
+ CPPUNIT_ASSERT(factor2 > 0.5);
+ // */
+}
+
+void
+SmallVectorTest::testSwapVectorContents()
+{
+ SmallVector<uint16_t, 8> v1;
+ SmallVector<uint16_t, 8> v2;
+
+ // v1 small enough to be contained in fixed array.
+ for (uint16_t i = 0; i < 6; ++i) {
+ v1.push_back(i);
+ }
+
+ // v2 big enough that it needs heap backed storage.
+ for (uint16_t i = 10; i < 30; ++i) {
+ v2.push_back(i);
+ }
+
+ vespalib::string expectedSmall("[0, 1, 2, 3, 4, 5]");
+ vespalib::string expectedBig("[10, 11, 12, 13, 14, 15, 16, 17, 18, 19, "
+ "20, 21, 22, 23, 24, 25, 26, 27, 28, 29]");
+
+ v1.swap(v2);
+
+ CPPUNIT_ASSERT_EQUAL(expectedSmall, v2.toString());
+ CPPUNIT_ASSERT_EQUAL(expectedBig, v1.toString());
+
+ swap(v1, v2);
+ CPPUNIT_ASSERT_EQUAL(expectedBig, v2.toString());
+ CPPUNIT_ASSERT_EQUAL(expectedSmall, v1.toString());
+}
+
+void
+SmallVectorTest::testErase()
+{
+ // Delete in small part of small array
+ {
+ SmallVector<uint16_t, 4> v = {3, 6, 5};
+ v.erase(v.begin());
+ CPPUNIT_ASSERT_EQUAL((SmallVector<uint16_t, 4>{6, 5}), v);
+ }
+ {
+ SmallVector<uint16_t, 4> v = {3, 6, 5};
+ v.erase(v.begin() + 1);
+ CPPUNIT_ASSERT_EQUAL((SmallVector<uint16_t, 4>{3, 5}), v);
+ }
+ {
+ SmallVector<uint16_t, 4> v = {3, 6, 5};
+ v.erase(v.begin() + 2);
+ CPPUNIT_ASSERT_EQUAL((SmallVector<uint16_t, 4>{3, 6}), v);
+ }
+
+ // Delete in small part of large array
+ {
+ SmallVector<uint16_t, 4> v = {3, 6, 5, 7, 8};
+ v.erase(v.begin());
+ CPPUNIT_ASSERT_EQUAL((SmallVector<uint16_t, 4>{6, 5, 7, 8}), v);
+ }
+ {
+ SmallVector<uint16_t, 4> v = {3, 6, 5, 7, 8};
+ v.erase(v.begin() + 1);
+ CPPUNIT_ASSERT_EQUAL((SmallVector<uint16_t, 4>{3, 5, 7, 8}), v);
+ }
+ {
+ SmallVector<uint16_t, 4> v = {3, 6, 5, 7, 8};
+ v.erase(v.begin() + 2);
+ CPPUNIT_ASSERT_EQUAL((SmallVector<uint16_t, 4>{3, 6, 7, 8}), v);
+ }
+
+ // Delete in extended part of small array
+ {
+ SmallVector<uint16_t, 1> v = {3, 6, 5};
+ v.erase(v.begin());
+ CPPUNIT_ASSERT_EQUAL((SmallVector<uint16_t, 1>{6, 5}), v);
+ }
+ {
+ SmallVector<uint16_t, 1> v = {3, 6, 5};
+ v.erase(v.begin() + 1);
+ CPPUNIT_ASSERT_EQUAL((SmallVector<uint16_t, 1>{3, 5}), v);
+ }
+ {
+ SmallVector<uint16_t, 1> v = {3, 6, 5};
+ v.erase(v.begin() + 2);
+ CPPUNIT_ASSERT_EQUAL((SmallVector<uint16_t, 1>{3, 6}), v);
+ }
+}
+
+namespace {
+ void foo(const SmallVector<uint16_t, 4>&) {
+ }
+}
+
+void
+SmallVectorTest::testCopy()
+{
+ foo(SmallVector<uint16_t, 4>{3, 2});
+ SmallVector<uint16_t, 4> v{1, 2, 3};
+ foo(v);
+ foo({});
+}
+
+} // lib
+} // storage
diff --git a/vdslib/src/tests/cpp-distribution.txt b/vdslib/src/tests/cpp-distribution.txt
new file mode 100644
index 00000000000..a61b0f19247
--- /dev/null
+++ b/vdslib/src/tests/cpp-distribution.txt
@@ -0,0 +1,100 @@
+3
+0
+2
+8
+5
+4
+1
+2
+2
+3
+5
+5
+8
+8
+0
+8
+3
+7
+5
+1
+1
+8
+8
+5
+0
+4
+1
+8
+4
+1
+5
+8
+5
+3
+1
+7
+8
+5
+2
+4
+8
+8
+4
+1
+7
+6
+5
+3
+0
+8
+1
+4
+5
+5
+8
+1
+2
+3
+6
+6
+3
+2
+4
+8
+2
+1
+1
+3
+6
+1
+0
+6
+4
+7
+5
+0
+8
+2
+7
+4
+0
+3
+1
+1
+3
+8
+4
+0
+5
+0
+8
+8
+1
+5
+7
+2
+6
+6
+5
+6
diff --git a/vdslib/src/tests/cpp-distribution2.txt b/vdslib/src/tests/cpp-distribution2.txt
new file mode 100644
index 00000000000..be9afabefe0
--- /dev/null
+++ b/vdslib/src/tests/cpp-distribution2.txt
@@ -0,0 +1,100 @@
+2
+1
+0
+2
+3
+2
+1
+0
+1
+2
+3
+2
+2
+1
+0
+2
+3
+3
+2
+0
+1
+2
+2
+2
+0
+2
+1
+3
+3
+0
+3
+1
+2
+3
+0
+3
+0
+2
+0
+2
+2
+0
+2
+0
+1
+3
+2
+3
+0
+1
+1
+3
+3
+3
+0
+1
+1
+2
+2
+0
+2
+0
+3
+3
+1
+0
+1
+2
+2
+0
+0
+1
+2
+3
+3
+0
+0
+0
+3
+2
+0
+3
+0
+0
+3
+1
+3
+0
+2
+1
+0
+3
+0
+3
+1
+0
+2
+0
+3
+0
diff --git a/vdslib/src/tests/cpp-hierarchical-distribution.txt b/vdslib/src/tests/cpp-hierarchical-distribution.txt
new file mode 100644
index 00000000000..b35e6e00c9f
--- /dev/null
+++ b/vdslib/src/tests/cpp-hierarchical-distribution.txt
@@ -0,0 +1,100 @@
+6
+3
+4
+2
+0
+8
+8
+2
+2
+8
+3
+8
+8
+2
+0
+8
+3
+2
+5
+6
+8
+2
+4
+8
+4
+8
+8
+0
+4
+8
+2
+8
+5
+0
+9
+2
+3
+9
+8
+8
+8
+4
+4
+5
+7
+0
+8
+0
+0
+8
+9
+0
+4
+2
+8
+8
+6
+6
+0
+6
+0
+7
+2
+0
+8
+5
+9
+0
+3
+6
+4
+6
+7
+2
+5
+3
+8
+5
+7
+0
+4
+6
+5
+6
+8
+9
+4
+0
+0
+0
+9
+3
+7
+0
+5
+7
+4
+6
+5
+9
diff --git a/vdslib/src/tests/distribution/.gitignore b/vdslib/src/tests/distribution/.gitignore
new file mode 100644
index 00000000000..583460ae288
--- /dev/null
+++ b/vdslib/src/tests/distribution/.gitignore
@@ -0,0 +1,3 @@
+*.So
+.depend
+Makefile
diff --git a/vdslib/src/tests/distribution/CMakeLists.txt b/vdslib/src/tests/distribution/CMakeLists.txt
new file mode 100644
index 00000000000..f3804b8b1eb
--- /dev/null
+++ b/vdslib/src/tests/distribution/CMakeLists.txt
@@ -0,0 +1,9 @@
+# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_library(vdslib_testdistribution
+ SOURCES
+ distributiontest.cpp
+ grouptest.cpp
+ idealnodecalculatorimpltest.cpp
+ idealnodecalculatorcachetest.cpp
+ DEPENDS
+)
diff --git a/vdslib/src/tests/distribution/bucketvector.cpp b/vdslib/src/tests/distribution/bucketvector.cpp
new file mode 100644
index 00000000000..789f85aa034
--- /dev/null
+++ b/vdslib/src/tests/distribution/bucketvector.cpp
@@ -0,0 +1,106 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#include <vespa/fastos/fastos.h>
+#include <tests/distribution/bucketvector.h>
+#include <limits>
+#include <iostream>
+#include <algorithm>
+#include <vespa/document/bucket/bucketid.h>
+
+
+namespace BucketVector{
+
+typedef document::BucketId::Type BidType;
+
+std::vector<BidType> v;
+uint64_t countBitsMask = 0x03FFFFFFFFFFFFFF;
+
+
+void reserve(size_t n)
+{
+ v.reserve(n);
+}
+
+void clear()
+{
+ v.clear();
+}
+
+void addBucket(uint64_t bucket)
+{
+ BidType b = document::BucketId::bucketIdToKey(bucket & countBitsMask);
+ v.push_back(b);
+}
+
+inline uint32_t getMax(uint32_t a, uint32_t b, uint32_t c){
+ if(a > b){
+ return (a>c)?a:c;
+ }
+ return (b>c)?b:c;
+}
+
+inline uint64_t getCountBitsMask(uint32_t countBits)
+{
+ uint64_t shift = 8 * sizeof(BidType) - countBits;
+ uint64_t mask = std::numeric_limits<uint64_t>::max() << shift;
+ mask = mask >> shift;
+ return mask;
+}
+
+
+inline uint32_t getLSBdiff(BidType a, BidType b)
+{
+ uint64_t mask = 0x0000000000000001;
+ uint32_t c = 1;
+
+ while((a&mask) == (b&mask)){
+ c++;
+ mask <<= 1;
+ }
+ return c;
+}
+
+void getBuckets(uint32_t distributionBits, std::vector<document::BucketId>& buckets){
+
+ if(v.size() == 0){
+ return;
+ }
+
+ std::sort(v.begin(), v.end());
+
+ uint32_t prevMSB = 1; //number of common MSB bits between current and previous bucket
+ uint32_t nextMSB; //number of common MSB bits between current and next bucket
+
+ size_t i=0;
+ for(; i<v.size()-1;i++){
+ if(v[i] == v[i+1]){
+ std::cerr << "identical buckets...bypassing\n";
+ continue;
+ }
+ nextMSB = getLSBdiff(document::BucketId::keyToBucketId(v[i]),
+ document::BucketId::keyToBucketId(v[i+1]));
+ BidType b = document::BucketId::keyToBucketId(v[i]);
+ uint32_t countBits = getMax(prevMSB, nextMSB, distributionBits);
+ uint64_t mask = getCountBitsMask(countBits);
+ buckets.push_back(document::BucketId(countBits, b&mask));
+ prevMSB = nextMSB;
+ }
+ nextMSB = 1;
+ uint32_t countBits = getMax(prevMSB, nextMSB, distributionBits);
+ uint64_t mask = getCountBitsMask(countBits);
+ BidType b = document::BucketId::keyToBucketId(v[i]);
+ buckets.push_back(document::BucketId(countBits, b&mask));
+}
+
+
+void printVector()
+{
+ for (size_t i=0; i < v.size(); i++){
+ std::cout << " " << v[i] << " " << document::BucketId::keyToBucketId(v[i]) << "\n";
+ }
+}
+
+
+
+}
+
+
diff --git a/vdslib/src/tests/distribution/bucketvector.h b/vdslib/src/tests/distribution/bucketvector.h
new file mode 100644
index 00000000000..b9499de933a
--- /dev/null
+++ b/vdslib/src/tests/distribution/bucketvector.h
@@ -0,0 +1,16 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#pragma once
+
+#include <vector>
+#include <vespa/document/bucket/bucketid.h>
+
+
+namespace BucketVector{
+
+ void reserve(size_t capacity);
+ void clear();
+ void addBucket(uint64_t bucket);
+ void getBuckets(uint32_t distributionBits, std::vector<document::BucketId>& buckets);
+ void printVector();
+}
+
diff --git a/vdslib/src/tests/distribution/datadistributiontest.cpp b/vdslib/src/tests/distribution/datadistributiontest.cpp
new file mode 100644
index 00000000000..8bdc1d86120
--- /dev/null
+++ b/vdslib/src/tests/distribution/datadistributiontest.cpp
@@ -0,0 +1,665 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#include <vespa/fastos/fastos.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <list>
+#include <vespa/document/bucket/bucketidfactory.h>
+#include <vespa/vdslib/distribution/distribution.h>
+#include <vespa/vdslib/state/clusterstate.h>
+#include <vespa/vdslib/state/random.h>
+#include <math.h>
+#include <ctime>
+#include <tests/distribution/bucketvector.h>
+#include <tests/distribution/randombucket.h>
+#include <fstream>
+
+using std::cout;
+using std::ios;
+using std::string;
+using std::vector;
+
+namespace storage {
+namespace lib {
+
+class DataDistribution_Test : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(DataDistribution_Test);
+// CPPUNIT_TEST(testDistributionBits);
+ CPPUNIT_TEST(testgqLargeScale);
+// CPPUNIT_TEST(testDiskFailure);
+// CPPUNIT_TEST(testBucketGeneration);
+// CPPUNIT_TEST(testDocSchemes);
+// CPPUNIT_TEST(testNodeCapacity);
+// CPPUNIT_TEST(testGetWaste);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+ DataDistribution_Test() : _distributionbits(16),
+ _gidbits(26),
+ _locationbits(32),
+ _scheme(DOC),
+ _num_users(1),
+ _index(0){}
+protected:
+
+ enum Scheme_t {DOC, USERDOC};
+
+ void testDistributionBits();
+ void testgqLargeScale();
+ void testDiskFailure();
+ void testDocSchemes();
+ void testBucketGeneration();
+ void testDiskDistributions();
+ void testNodeCapacity();
+ void testGetWaste();
+ void testDiskDistribution(vespa::config::content::StorDistributionConfig::DiskDistribution, string dist_name);
+ string getFileName(string params);
+ void getDistribution(const vector<document::BucketId>& buckets,
+ vector<vector<float> >& nodes_disks,
+ vespa::config::content::StorDistributionConfig::DiskDistribution,
+ ClusterState state);
+ vector<document::BucketId> generateBuckets(uint64_t n);
+ void writeToFile(string file_name, vector<vector<float> >& results, int max_times);
+ void moment(vector<float>& data, vector<float>& capacities, float* waste);
+
+ uint32_t _distributionbits;
+ uint32_t _gidbits;
+ uint32_t _locationbits;
+ Scheme_t _scheme;
+ uint64_t _num_users;
+ uint16_t _index;
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION( DataDistribution_Test );
+
+
+uint64_t cumulativePick(vector<float> capacity, RandomGen* rg);
+vector<uint64_t> pickN(uint64_t n, vector<float> capacity);
+ClusterState createClusterState(uint64_t num_nodes, uint64_t num_disks_per_node, vector<uint64_t>& failed_disks, vector<float> node_capacity);
+void printVector(vector<uint64_t> v);
+void printVector(vector<float> v);
+void printVector(vector<vector<float> > v);
+vector<float> filterFailedDisks(vector<vector<float> >& distribution, vector<uint64_t> indexes);
+vector<float> filterFailedDisks(vector<float>& disks, vector<uint64_t> indexes);
+string getFileName(string params);
+vector<float> getCapacity(uint64_t n, float min_capacity, float max_capacity);
+int readBucketsFromFile(std::string file, vector<document::BucketId>& buckets);
+void getDisks(const vector<vector<float> >& distribution, vector<float>& disks);
+
+void DataDistribution_Test::testBucketGeneration()
+{
+
+ _index=0;
+ uint64_t total_buckets = 50000000;
+
+ vector<document::BucketId> buckets_doc;
+ vector<document::BucketId> buckets_userdoc;
+ vector<uint32_t> countbits_doc(58,0);
+ vector<uint32_t> countbits_userdoc(58,0);
+
+ //generate buckets with doc scheme
+ _scheme = DOC;
+ buckets_doc = generateBuckets(total_buckets);
+ for(size_t i=0; i < buckets_doc.size(); i++){
+ countbits_doc[buckets_doc[i].getUsedBits()]++;
+ }
+
+ //generate buckets with userdoc scheme
+ _scheme = USERDOC;
+ _num_users = static_cast<uint64_t>(1.5*total_buckets);
+ buckets_userdoc = generateBuckets(total_buckets);
+ for(size_t i=0; i < buckets_userdoc.size(); i++){
+ countbits_userdoc[buckets_userdoc[i].getUsedBits()]++;
+ }
+
+ // write data to file
+ std::ostringstream ost;
+ ost << "buckets-generation";
+ string file_name = getFileName(ost.str());
+ FastOS_File file;
+ CPPUNIT_ASSERT(file.OpenWriteOnlyTruncate(file_name.c_str()));
+ for(size_t i=0; i < countbits_doc.size(); i++){
+ std::ostringstream ost2;
+ ost2 << countbits_doc[i] << " " << countbits_userdoc[i] << "\n";
+ std::cerr << countbits_doc[i] << " " << countbits_userdoc[i] << "\n";
+ CPPUNIT_ASSERT(file.CheckedWrite(ost2.str().c_str(), ost2.str().size()));
+ }
+ CPPUNIT_ASSERT(file.Close());
+}
+
+
+void getDisks(const vector<vector<float> >& distribution, vector<float>& disks)
+{
+ for(size_t i=0; i < distribution.size();i++){
+ for(size_t j=0; j < distribution[i].size();j++){
+ disks.push_back(distribution[i][j]);
+ }
+ }
+}
+
+int readBucketsFromFile(std::string file, vector<document::BucketId>& buckets)
+{
+ std::string line;
+ std::ifstream ifs;
+ ifs.open(file.c_str(), ios::in);
+ if (ifs.is_open()){
+ uint64_t b;
+ while (ifs >> b) {
+ buckets.push_back(document::BucketId(b));
+ }
+ ifs.close();
+ return 1;
+ }
+ else cout << "Unable to open file";
+
+ return 0;
+}
+
+vector<document::BucketId> DataDistribution_Test::generateBuckets(uint64_t n)
+{
+ std::cerr << "Generating " << n << " buckets...\n";
+ if(_scheme == USERDOC){
+ RandomBucket::setUserDocScheme(_num_users, _locationbits);
+ }
+ else{
+ RandomBucket::setDocScheme();
+ }
+
+ RandomBucket::setSeed();
+
+ BucketVector::reserve(n);
+
+ for(uint64_t i=0; i < n; i++){
+ uint64_t u = RandomBucket::get();
+ BucketVector::addBucket(u);
+ }
+
+ vector<document::BucketId> buckets;
+ BucketVector::getBuckets(_distributionbits, buckets);
+ BucketVector::clear();
+
+
+
+ vector<uint64_t> countbits(58,0);
+ for(size_t i=0; i < buckets.size(); i++){
+ countbits[buckets[i].getUsedBits()]++;
+ }
+ printVector(countbits);
+ std::cerr << "Generating buckets...DONE\n";
+
+ return buckets;
+}
+
+
+void DataDistribution_Test::testDistributionBits()
+{
+ uint64_t num_disks_per_node=11;
+ uint64_t num_buckets_per_disk=100000;
+ uint64_t num_copies = 2;
+ _scheme = USERDOC;
+ float waste;
+
+ for(uint64_t num_nodes=40; num_nodes <= 100; num_nodes+=20){
+ vector<vector<float> > distribution(num_nodes, vector<float>(num_disks_per_node));
+ uint64_t total_buckets = num_nodes*num_disks_per_node*num_buckets_per_disk/num_copies;
+ _num_users = static_cast<uint64_t>(1.5*total_buckets);
+ vector<float> disk_capacity(num_disks_per_node*num_nodes, 1.0);
+ vector<uint64_t> failed_disks;
+ vector<float> node_capacity = getCapacity(num_nodes, 1.0, 1.0);
+ ClusterState state = createClusterState(num_nodes, num_disks_per_node, failed_disks, node_capacity);
+ std::cerr << "testing " << state << "\n";
+ vector<document::BucketId> buckets = generateBuckets(total_buckets);
+ std::cerr << "Get distribution...\n";
+ getDistribution(buckets, distribution, vespa::config::content::StorDistributionConfig::MODULO_INDEX, state);
+ std::cerr << "Get distribution...DONE\n";
+ vector<float> disks;
+ getDisks(distribution, disks);
+
+ printVector(disks);
+ moment(disks, disk_capacity, &waste);
+ std::cerr << "waste=" << waste << "\n";
+ }
+
+
+}
+
+void DataDistribution_Test::testgqLargeScale()
+{
+ uint64_t num_disks_per_node=11;
+ uint64_t num_copies = 2;
+ uint64_t num_buckets_per_disk = 115000;
+ _scheme = USERDOC;
+
+ {
+ string file_name = "waste_modulo_index_used_bits";
+ FastOS_File file;
+ CPPUNIT_ASSERT(file.OpenWriteOnlyTruncate(file_name.c_str()));
+
+ for(uint64_t nodes=201; nodes <= 1000; nodes++){
+ uint64_t total_buckets = nodes*num_disks_per_node*num_buckets_per_disk/num_copies;
+ _num_users = static_cast<uint64_t>(1.5*total_buckets);
+ vector<document::BucketId> buckets = generateBuckets(total_buckets);
+
+ std::ostringstream ost;
+ ost << "storage:" << nodes;
+ ClusterState state(ost.str());
+ float waste_mod, waste_used(0);
+// {
+// document::BucketIdFactory bucketIdFactory(_distributionbits, _gidbits, document::BucketConfig::USED_BITS);
+// vector<vector<float> > distribution(nodes, vector<float>(11));
+// getDistribution(buckets, distribution, bucketIdFactory, state);
+//
+// vector<float> distribution2;
+// getDisks(distribution, distribution2);
+//
+// vector<float> disk_capacity(num_disks_per_node*nodes, 1.0);
+// moment(distribution2, disk_capacity, &waste_used);
+// }
+ std::cerr << "modulo_index DONE, waste:" << waste_mod << "\n";
+ {
+ vector<vector<float> > distribution(nodes, vector<float>(11));
+ getDistribution(buckets, distribution, vespa::config::content::StorDistributionConfig::MODULO_INDEX, state);
+
+ vector<float> distribution2;
+ getDisks(distribution, distribution2);
+
+ vector<float> disk_capacity(num_disks_per_node*nodes, 1.0);
+ moment(distribution2, disk_capacity, &waste_mod);
+ }
+
+ std::ostringstream ost2;
+ ost2 << nodes << " " << waste_mod << " " << waste_used << "\n";
+ std::cerr << nodes << " " << waste_mod << " " << waste_used << "\n";
+ CPPUNIT_ASSERT(file.CheckedWrite(ost2.str().c_str(), ost2.str().size()));
+ }
+ CPPUNIT_ASSERT(file.Close());
+ }
+}
+
+
+void DataDistribution_Test::testDiskFailure()
+{
+ int num_disks_per_node=2;
+ int num_nodes = 2;
+
+ ClusterState state("storage: 2 .0.d:2 .0.d.0:d");
+
+ _scheme = DOC;
+ uint64_t total_buckets=1000000;
+ vector<document::BucketId> buckets = generateBuckets(total_buckets);
+
+ vector<float> disk_capacity(num_disks_per_node*num_nodes-1, 1.0);
+ vector<uint64_t> failed_disks(1,0);
+ float waste;
+ {
+ vector<vector<float> > distribution(num_nodes, vector<float>(2));
+ getDistribution(buckets, distribution, vespa::config::content::StorDistributionConfig::MODULO, state);
+ printVector(distribution);
+
+ vector<float> distribution2 = filterFailedDisks(distribution, failed_disks);
+
+ printVector(distribution2);
+ moment(distribution2, disk_capacity, &waste);
+ std::cerr << "waste=" << waste << "\n";
+ }
+ {
+ vector<vector<float> > distribution(num_nodes, vector<float>(2));
+ getDistribution(buckets, distribution, vespa::config::content::StorDistributionConfig::MODULO_INDEX, state);
+ printVector(distribution);
+
+ vector<float> distribution2 = filterFailedDisks(distribution, failed_disks);
+
+ printVector(distribution2);
+ moment(distribution2, disk_capacity, &waste);
+ std::cerr << "waste=" << waste << "\n";
+ }
+ {
+ vector<vector<float> > distribution(num_nodes, vector<float>(2));
+ getDistribution(buckets, distribution, vespa::config::content::StorDistributionConfig::MODULO_KNUTH, state);
+ printVector(distribution);
+
+ vector<float> distribution2 = filterFailedDisks(distribution, failed_disks);
+
+ printVector(distribution2);
+ moment(distribution2, disk_capacity, &waste);
+ std::cerr << "waste=" << waste << "\n";
+ }
+}
+
+
+void DataDistribution_Test::testDocSchemes()
+{
+ _index=1;
+ _scheme = DOC;
+ testDiskDistributions();
+
+ _scheme = USERDOC;
+ testDiskDistributions();
+}
+
+void DataDistribution_Test::testDiskDistributions()
+{
+ {
+ testDiskDistribution(vespa::config::content::StorDistributionConfig::MODULO, "modulo" );
+ }
+
+ {
+ testDiskDistribution(vespa::config::content::StorDistributionConfig::MODULO_INDEX, "modulo_index" );
+ }
+
+ {
+ testDiskDistribution(vespa::config::content::StorDistributionConfig::MODULO_KNUTH, "modulo_knuth");
+ }
+
+
+}
+
+
+void DataDistribution_Test::testNodeCapacity()
+{
+ _index=1;
+ {
+ _scheme = DOC;
+ testDiskDistribution(vespa::config::content::StorDistributionConfig::MODULO_INDEX, "capacity");
+ }
+ {
+ _scheme = USERDOC;
+ testDiskDistribution(vespa::config::content::StorDistributionConfig::MODULO_INDEX, "capacity");
+ }
+}
+
+
+
+void DataDistribution_Test::testDiskDistribution(vespa::config::content::StorDistributionConfig::DiskDistribution diskDistribution, string dist_name)
+{
+ uint64_t num_buckets_per_disk = 10000;
+
+ for(uint64_t num_copies=0; num_copies <= 3; num_copies++){
+ num_buckets_per_disk = num_buckets_per_disk/num_copies;
+ for(uint64_t num_failures=0; num_failures <= 5; num_failures++){
+ vector<vector<float> > results(20, vector<float>(10, 0.0));
+ std::ostringstream ost;
+ ost << num_copies<< "copy_";
+ ost << num_failures <<"faileddisks_";
+ ost << "["<< 1 <<","<< 1 <<"]dcap_";
+ ost << "["<< 1 <<","<< 1 <<"]ncap";
+ ost << dist_name << "_";
+ string file_name = getFileName(ost.str());
+ for(uint64_t num_times=1; num_times <= 3; num_times++){
+ std::cerr << file_name << " " << num_times << " time\n";
+ for(uint64_t num_nodes=1; num_nodes <= 20; num_nodes++){
+ for(uint64_t num_disks_per_node=1; num_disks_per_node <= 10; num_disks_per_node++){
+ uint64_t num_total_buckets = num_nodes*num_disks_per_node*num_buckets_per_disk;
+ vector<float> disk_capacity(num_disks_per_node*num_nodes, 1.0);
+ vector<uint64_t> failed_disks = pickN(num_failures, disk_capacity);
+ std::sort(failed_disks.begin(), failed_disks.end());
+ vector<float> node_capacity = getCapacity(num_nodes, 1, 1);
+ ClusterState state = createClusterState(num_nodes, num_disks_per_node, failed_disks, node_capacity);
+ vector<document::BucketId> buckets = generateBuckets(num_total_buckets);
+ vector<vector<float> > distribution;
+ getDistribution(buckets, distribution, diskDistribution, state);
+ //std::cerr << "2D dist:\n";
+ //printVector(distribution);
+
+ for(uint64_t i=0; i<num_nodes; i++){
+ for(uint64_t j=0; j<num_disks_per_node ; j++){
+ disk_capacity[i*num_disks_per_node+j] = node_capacity[i]/num_disks_per_node;
+ }
+ }
+ //std::cerr << "failed disks: ";
+ //printVector(failed_disks);
+ //std::cerr << "disks capac:\n";
+ //printVector(disk_capacity);
+ vector<float> distribution2 = filterFailedDisks(distribution, failed_disks);
+ std::cerr << "dist2: ";
+ printVector(distribution2);
+
+ vector<float> disk_capacity2 = filterFailedDisks(disk_capacity, failed_disks);
+ //std::cerr << "disks2 capac:\n";
+ //printVector(disk_capacity2);
+ float waste;
+ moment(distribution2, disk_capacity2, &waste);
+
+ results[num_nodes-1][num_disks_per_node-1] += waste;
+ std::cerr << num_nodes << " " << num_disks_per_node << " " << waste << " \n";
+ }
+ }
+ }
+ writeToFile(file_name, results, 3);
+ }
+ }
+}
+
+
+void DataDistribution_Test::writeToFile(string file_name, vector<vector<float> >& results, int max_times)
+{
+ fprintf(stderr, "%s\n", file_name.c_str());
+ FastOS_File file;
+ CPPUNIT_ASSERT(file.OpenWriteOnlyTruncate(file_name.c_str()));
+ for(size_t node=1; node <= results.size(); node++){
+ for(uint64_t disk=1; disk <= results[node].size(); disk++){
+ std::ostringstream ost;
+ ost << node << " " << disk << " " << results[node-1][disk-1]/max_times << "\n";
+ std::cerr << node << " " << disk << " " << results[node-1][disk-1]/max_times << "\n";
+ CPPUNIT_ASSERT(file.CheckedWrite(ost.str().c_str(), ost.str().size()));
+ }
+ }
+ CPPUNIT_ASSERT(file.Close());
+}
+
+void DataDistribution_Test::getDistribution(
+ const vector<document::BucketId>& buckets,
+ vector<vector<float> >& nodes_disks,
+ vespa::config::content::StorDistributionConfig::DiskDistribution diskDistribution,
+ ClusterState state)
+{
+ vector<uint16_t> copies;
+
+ Distribution distr(Distribution::getDefaultDistributionConfig(
+ 3, state.getNodeCount(NodeType::STORAGE), diskDistribution));
+
+ NodeState nodeState;
+ for (size_t i = 0; i < buckets.size(); i++) {
+ copies = distr.getIdealStorageNodes(state, buckets[i], "u");
+
+ for (unsigned k = 0; k < copies.size(); k++) {
+ uint16_t node_index = copies[k];
+ nodeState.setDiskCount(nodes_disks[node_index].size());
+ uint16_t disk_index = distr.getIdealDisk(
+ nodeState, node_index, buckets[i]);
+ nodes_disks[node_index][disk_index]++;
+ }
+ }
+}
+
+void scaleCapacity(vector<vector<float> >& distribution, vector<float>& capacity)
+{
+ for(size_t i=0; i< distribution.size(); i++){
+ for(size_t j=0; j< distribution[i].size(); j++){
+ distribution[i][j] = distribution[i][j]/capacity[i];
+ }
+ }
+}
+
+vector<float> getCapacity(uint64_t n, float min_capacity, float max_capacity)
+{
+ vector<float> capacity(n, 1.0);
+ if(min_capacity == max_capacity){
+ return capacity;
+ }
+ RandomGen rg(0);
+ for(uint64_t i=0; i < n; i++){
+ float r = rg.nextDouble();
+ capacity[i] = min_capacity + r*(max_capacity-min_capacity);
+ }
+ return capacity;
+
+}
+
+vector<float> filterFailedDisks(vector<vector<float> >& distribution, vector<uint64_t> indexes)
+{
+ vector<float> distribution2;
+ uint64_t d=0;
+ for(size_t i=0; i< distribution.size(); i++){
+ for(size_t j=0; j< distribution[i].size(); j++){
+ if(d == indexes.size() || (i*distribution[i].size()+j) != indexes[d]){
+ distribution2.push_back(distribution[i][j]);
+ }
+ else{
+ d++;
+ }
+ }
+ }
+ return distribution2;
+}
+
+vector<float> filterFailedDisks(vector<float>& disks, vector<uint64_t> indexes)
+{
+ vector<float> disks2;
+ uint64_t d=0;
+ for(size_t i=0; i< disks.size(); i++){
+ if(d == indexes.size() || i != indexes[d]){
+ disks2.push_back(disks[i]);
+ }
+ else{
+ d++;
+ }
+ }
+ return disks2;
+}
+
+
+string DataDistribution_Test::getFileName(string params)
+{
+ string scheme = (_scheme == DOC) ? "doc" : "userdoc";
+ std::ostringstream ost;
+ ost << "datadistribution_" << _index << "_" << scheme << "_" << params << ".dat";
+ return ost.str();
+}
+
+
+void printVector(vector<float> v)
+{
+ for(size_t i=0; i < v.size();i++){
+ std::cerr << v[i] << " ";
+ }
+ std::cerr << "\n";
+}
+
+
+void printVector(vector<uint64_t> v)
+{
+ for(size_t i=0; i < v.size();i++){
+ std::cerr << v[i] << " ";
+ }
+ std::cerr << "\n";
+}
+
+
+void printVector(vector<vector<float> > v)
+{
+ for(size_t i=0; i < v.size();i++){
+ for(size_t j=0; j < v[i].size();j++){
+ std::cerr << v[i][j] << "\n";
+ }
+ }
+}
+
+//pick N elements (indexes) with capacity weights
+vector<uint64_t> pickN(uint64_t n, vector<float> capacity)
+{
+ vector<uint64_t> picked;
+ // Initialize random generator
+ RandomGen rg;
+
+ if(n > capacity.size()){
+ n = capacity.size();
+ }
+
+ for(size_t i=0; i<capacity.size(); i++){
+ uint64_t x = cumulativePick(capacity, &rg);
+ picked.push_back(x);
+ capacity[x] = 0;
+ }
+ return picked;
+}
+
+
+uint64_t cumulativePick(vector<float> capacity, RandomGen* rg)
+{
+ uint64_t picked = 0;
+ float s=0.0;
+
+ for(size_t i=0; i< capacity.size(); i++){
+ float r = rg->nextDouble();
+ if(capacity[i] > 0){
+ s+=capacity[i];
+ if(r < (capacity[i]/s) ){
+ picked = i;
+ }
+ }
+ }
+ return picked;
+}
+
+void DataDistribution_Test::moment(vector<float>& data, vector<float>& capacities, float* waste)
+{
+
+ *waste = 0.0;
+ if(!data.empty() || data.size() == 1){
+ if(data.size() != capacities.size()){
+ std::cerr << "data: ";
+ printVector(data);
+ std::cerr << "capacities: ";
+ printVector(capacities);
+ }
+ CPPUNIT_ASSERT(data.size() == capacities.size());
+ uint64_t i_max=0;
+ for (size_t i=1; i<data.size(); i++){
+ CPPUNIT_ASSERT(capacities[i] != 0);
+ if((data[i_max]/capacities[i_max]) < (data[i]/capacities[i])){
+ i_max = i;
+ }
+ }
+
+ float waste_coef = data[i_max]/capacities[i_max];
+
+ float s = 0.0;
+ for (size_t i=0; i<data.size(); i++){
+ *waste += waste_coef*capacities[i]-data[i];
+ s+=waste_coef*capacities[i];
+ }
+ *waste /= (s == 0)? 1 : s;
+ }
+}
+
+ClusterState createClusterState(uint64_t num_nodes, uint64_t num_disks_per_node, vector<uint64_t>& failed_disks, vector<float> node_capacity)
+{
+ std::ostringstream ost;
+ uint64_t node;
+
+ ost << "storage:" << num_nodes;
+
+ uint64_t j = 0;
+ for (uint64_t i = 0; i < num_nodes; i++) {
+ if(!node_capacity.empty() && node_capacity[i] != 1.0){
+ ost << " ." << i <<".c:"<< node_capacity[i];
+ }
+ if(!failed_disks.empty()){
+ node = failed_disks[j]/num_disks_per_node;
+ if(node == i){
+ ost << " ." << node <<".d:"<< num_disks_per_node ;
+ while (node == i && j < failed_disks.size()) {
+ ost << " ." << node << ".d." << failed_disks[j]%num_disks_per_node<<":d";
+ j++;
+ node = failed_disks[j]/num_disks_per_node;
+ }
+ }
+ }
+ }
+ //std::cerr << "Creating system state: "<< ost.str() << "\n";
+
+ return ClusterState(ost.str());
+
+}
+
+} // lib
+} // storage
diff --git a/vdslib/src/tests/distribution/distributiontest.cpp b/vdslib/src/tests/distribution/distributiontest.cpp
new file mode 100644
index 00000000000..6103762abd8
--- /dev/null
+++ b/vdslib/src/tests/distribution/distributiontest.cpp
@@ -0,0 +1,1507 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/fastos/fastos.h>
+#include <vespa/vdslib/distribution/distribution.h>
+#include <vespa/vdslib/distribution/idealnodecalculator.h>
+#include <boost/assign.hpp>
+#include <vespa/config/helper/configfetcher.h>
+#include <cmath>
+#include <chrono>
+#include <thread>
+#include <fstream>
+#include <stdlib.h>
+#include <vespa/vespalib/data/slime/slime.h>
+#include <vespa/vespalib/io/fileutil.h>
+#include <vespa/vespalib/text/stringtokenizer.h>
+#include <vespa/vespalib/util/regexp.h>
+#include <vespa/vespalib/stllike/lexical_cast.h>
+#include <vespa/vdslib/state/clusterstate.h>
+#include <vespa/vdstestlib/cppunit/macros.h>
+
+namespace storage {
+namespace lib {
+
+struct DistributionTest : public CppUnit::TestFixture {
+ void testVerifyJavaDistributions();
+ void testVerifyJavaDistributions2();
+ void testDiskSkewLocal();
+ void testDiskSkewGlobal();
+ void testDiskIntersection();
+ void testDown();
+ void testInitializing();
+ void testDiskDown();
+ void testDiskDownMaintenance();
+ void testDiskCapacityWeights();
+ void testUnchangedDistribution();
+
+ void testSerializeDeserialize();
+
+ void testSkew();
+ void testDistribution();
+ void testGreedyDistribution();
+ void testSkewWithDown();
+ void testMove();
+ void testMoveConstraints();
+ void testMinimalDataMovement();
+ void testDistributionBits();
+
+ void testRedundancyHierarchicalDistribution();
+ void testHierarchicalDistribution();
+ void testHierarchicalDistributionPerformance();
+ void testHierarchicalNoRedistribution();
+ void testGroupCapacity();
+
+ void testHighSplitBit();
+
+ void testActivePerGroup();
+ void testHierarchicalDistributeLessThanRedundancy();
+
+ void testEmptyAndCopy();
+
+ CPPUNIT_TEST_SUITE(DistributionTest);
+ CPPUNIT_TEST(testVerifyJavaDistributions);
+ CPPUNIT_TEST(testVerifyJavaDistributions2);
+ CPPUNIT_TEST(testDiskSkewLocal);
+ CPPUNIT_TEST(testDiskSkewGlobal);
+ CPPUNIT_TEST(testDiskIntersection);
+ CPPUNIT_TEST(testMove);
+ CPPUNIT_TEST(testMoveConstraints);
+ CPPUNIT_TEST(testDown);
+ CPPUNIT_TEST(testInitializing);
+ CPPUNIT_TEST(testDiskDown);
+ CPPUNIT_TEST(testDiskDownMaintenance);
+ CPPUNIT_TEST(testDiskCapacityWeights);
+ CPPUNIT_TEST(testUnchangedDistribution);
+ CPPUNIT_TEST(testSerializeDeserialize);
+
+ CPPUNIT_TEST(testRedundancyHierarchicalDistribution);
+ CPPUNIT_TEST(testHierarchicalDistribution);
+ // CPPUNIT_TEST(testHierarchicalDistributionPerformance);
+ CPPUNIT_TEST(testHierarchicalNoRedistribution);
+ CPPUNIT_TEST(testHierarchicalDistributeLessThanRedundancy);
+ CPPUNIT_TEST(testDistributionBits);
+ CPPUNIT_TEST(testGroupCapacity);
+
+ CPPUNIT_TEST(testHighSplitBit);
+ CPPUNIT_TEST(testActivePerGroup);
+
+ // Skew tests. Should probably be in separate test file.
+ /*
+ CPPUNIT_TEST(testSkew);
+ CPPUNIT_TEST(testDistribution);
+ CPPUNIT_TEST(testGreedyDistribution);
+ CPPUNIT_TEST(testSkewWithDown);
+ */
+
+ CPPUNIT_TEST_SUITE_END();
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(DistributionTest);
+
+template <typename T>
+T readConfig(const config::ConfigUri & uri)
+{
+ return *config::ConfigGetter<T>::getConfig(uri.getConfigId(), uri.getContext());
+}
+
+void
+DistributionTest::testVerifyJavaDistributions()
+{
+ std::vector<std::string> tests;
+ tests.push_back("capacity");
+ tests.push_back("depth2");
+ tests.push_back("depth3");
+ tests.push_back("retired");
+ for (uint32_t i=0; i<tests.size(); ++i) {
+ std::string test = tests[i];
+ ClusterState state;
+ {
+ std::ifstream in(
+ ("distribution/testdata/java_" + test + ".state").c_str());
+ std::string mystate;
+ in >> mystate;
+ in.close();
+ state = ClusterState(mystate);
+ }
+ Distribution distr(readConfig<vespa::config::content::StorDistributionConfig>(
+ "file:distribution/testdata/java_" + test + ".cfg"));
+ std::ofstream of(
+ ("distribution/testdata/cpp_" + test + ".distribution").c_str());
+
+ long maxBucket = 1;
+ long mask = 0;
+ for (uint32_t distributionBits = 0; distributionBits <= 32;
+ ++distributionBits)
+ {
+ state.setDistributionBitCount(distributionBits);
+ RandomGen randomizer(distributionBits);
+ for (uint32_t bucketIndex = 0; bucketIndex < 64; ++bucketIndex) {
+ if (bucketIndex >= maxBucket) break;
+ uint64_t bucketId = bucketIndex;
+ // Use random bucket if we dont test all
+ if (maxBucket > 64) {
+ bucketId = randomizer.nextUint64();
+ }
+ document::BucketId bucket(distributionBits, bucketId);
+ for (uint32_t redundancy = 1;
+ redundancy <= distr.getRedundancy(); ++redundancy)
+ {
+ int distributorIndex = distr.getIdealDistributorNode(
+ state, bucket, "uim");
+ of << distributionBits << " " << (bucketId & mask)
+ << " " << redundancy << " " << distributorIndex << "\n";
+ }
+ }
+ mask = (mask << 1) | 1;
+ maxBucket = maxBucket << 1;
+ }
+ of.close();
+ std::ostringstream cmd;
+ cmd << "diff -u distribution/testdata/cpp_" << test << ".distribution "
+ << "distribution/testdata/java_" << test << ".distribution";
+ int result = system(cmd.str().c_str());
+ CPPUNIT_ASSERT_EQUAL_MSG("Failed distribution sync test: " + test,
+ 0, result);
+ }
+}
+
+namespace {
+ struct ExpectedResult {
+ document::BucketId bucket;
+ IdealNodeList nodes;
+ vespalib::string failure;
+ };
+ void verifyJavaDistribution(
+ const vespalib::string& name,
+ const ClusterState& state,
+ const Distribution& distribution,
+ const NodeType& nodeType,
+ uint16_t redundancy,
+ uint16_t nodeCount,
+ vespalib::stringref upStates,
+ const std::vector<ExpectedResult> results)
+ {
+ (void) nodeCount;
+ for (uint32_t i=0, n=results.size(); i<n; ++i) {
+ std::string testId = name + " " + results[i].bucket.toString();
+ try{
+ std::vector<uint16_t> nvect;
+ distribution.getIdealNodes(nodeType, state, results[i].bucket,
+ nvect, upStates.c_str(), redundancy);
+ IdealNodeList nodes;
+ for (uint32_t j=0, m=nvect.size(); j<m; ++j) {
+ nodes.push_back(Node(nodeType, nvect[j]));
+ }
+ /*
+ if (results[i].nodes.toString() != nodes.toString()) {
+ std::cerr << "Failure: " << testId << " "
+ << results[i].nodes.toString() << " in java but "
+ << nodes.toString() << " in C++.\n";
+ }// */
+ //*
+ CPPUNIT_ASSERT_EQUAL_MSG(testId,
+ results[i].nodes.toString(), nodes.toString());
+ // */
+ if (results[i].nodes.size() > 0) {
+ CPPUNIT_ASSERT_EQUAL_MSG(testId, vespalib::string("NONE"),
+ results[i].failure);
+ } else {
+ CPPUNIT_ASSERT_EQUAL_MSG(testId,
+ vespalib::string("NO_DISTRIBUTORS_AVAILABLE"),
+ results[i].failure);
+ }
+ } catch (vespalib::Exception& e) {
+ CPPUNIT_ASSERT_EQUAL_MSG(testId, results[i].failure,
+ e.getMessage());
+ }
+ }
+ }
+} // anonymous
+
+auto readFile(const std::string & filename) {
+ vespalib::File file(filename);
+ file.open(vespalib::File::READONLY);
+
+ std::vector<char> buf(file.getFileSize());
+ off_t read = file.read(&buf[0], buf.size(), 0);
+
+ CPPUNIT_ASSERT_EQUAL(read, file.getFileSize());
+ return std::move(buf);
+}
+
+void
+DistributionTest::testVerifyJavaDistributions2()
+{
+ vespalib::DirectoryList files(
+ vespalib::listDirectory("distribution/testdata"));
+ for (uint32_t i=0, n=files.size(); i<n; ++i) {
+ size_t pos = files[i].find(".java.results");
+ if (pos == vespalib::string::npos || pos + 13 != files[i].size()) {
+ //std::cerr << "Skipping unmatched file '" << files[i] << "'.\n";
+ continue;
+ }
+
+ vespalib::string name(files[i].substr(0, pos));
+ using namespace vespalib::slime;
+ vespalib::Slime slime;
+
+ auto buf = readFile("distribution/testdata/" + files[i]);
+ auto size = JsonFormat::decode({&buf[0], buf.size()}, slime);
+
+ if (size == 0) {
+ std::cerr << "\n\nSize of " << files[i] << " is 0. Maybe is not generated yet? Taking a 5 second nap!";
+ std::this_thread::sleep_for(std::chrono::seconds(5));
+
+ buf = readFile("distribution/testdata/" + files[i]);
+ size = JsonFormat::decode({&buf[0], buf.size()}, slime);
+
+ if (size == 0) {
+ std::cerr << "\n\nError verifying " << files[i] << ". File doesn't exist or is empty";
+ }
+ }
+
+ CPPUNIT_ASSERT(size != 0);
+ Cursor& c(slime.get());
+
+ ClusterState cs(c["cluster-state"].asString().make_string());
+ std::string distConfig(c["distribution"].asString().make_string());
+ Distribution d(distConfig);
+ const NodeType& nt(
+ NodeType::get(c["node-type"].asString().make_string()));
+ uint32_t redundancy(c["redundancy"].asLong());
+ uint32_t nodeCount(c["node-count"].asLong());
+ vespalib::string upStates(c["up-states"].asString().make_string());
+ std::vector<ExpectedResult> results;
+ for (uint32_t j=0, m=c["result"].entries(); j<m; ++j) {
+ Cursor& e(c["result"][j]);
+ ExpectedResult result;
+ std::string bucketString(e["bucket"].asString().make_string());
+ char *end = 0;
+ uint64_t rawBucket = strtoull(bucketString.c_str(), &end, 16);
+ CPPUNIT_ASSERT_EQUAL(int(0), int(*end));
+ result.bucket = document::BucketId(rawBucket);
+ result.failure = e["failure"].asString().make_string();
+ for (uint32_t k=0; k<e["nodes"].entries(); ++k) {
+ result.nodes.push_back(Node(nt, e["nodes"][k].asLong()));
+ }
+ results.push_back(result);
+ }
+ verifyJavaDistribution(name, cs, d, nt, redundancy, nodeCount,
+ upStates, results);
+ //std::cerr << name << ": Verified " << results.size() << " tests.\n";
+ }
+}
+
+void
+DistributionTest::testUnchangedDistribution()
+{
+ ClusterState state("distributor:10 storage:10");
+
+ Distribution distr(Distribution::getDefaultDistributionConfig(3, 10));
+ std::ifstream in("distribution/testdata/41-distributordistribution");
+
+ for (unsigned i = 0; i < 65536; i++) {
+ uint16_t node = distr.getIdealDistributorNode(
+ state, document::BucketId(16, i), "u");
+
+ char buf[100];
+ in.getline(buf, 100);
+
+ CPPUNIT_ASSERT_EQUAL(atoi(buf), (int)node);
+ }
+}
+
+namespace {
+ struct Test {
+ const NodeType* _nodeType;
+ std::string _state;
+ Distribution::DistributionConfig _distributionConfig;
+ std::unique_ptr<Distribution> _distribution;
+ uint32_t _bucketsToTest;
+ const char* _upStates;
+ uint16_t _redundancy;
+
+ Test()
+ : _nodeType(&NodeType::STORAGE),
+ _state("distributor:10 storage:10"),
+ _distributionConfig(
+ Distribution::getDefaultDistributionConfig(3, 10)),
+ _distribution(new Distribution(_distributionConfig)),
+ _bucketsToTest(100),
+ _upStates("uir"),
+ _redundancy(2)
+ {
+ }
+
+ Test& state(const std::string& s) {
+ _state = s;
+ return *this;
+ }
+
+ Test& upStates(const char* ups) {
+ _upStates = ups;
+ return *this;
+ }
+
+ Test& nodeType(const NodeType& type) {
+ _nodeType = &type;
+ return *this;
+ }
+
+ Test& distribution(Distribution* d) {
+ _distribution.reset(d);
+ return *this;
+ }
+
+ std::vector<uint16_t> getNodeCounts() const {
+ std::vector<uint16_t> result(10, 0);
+ for (uint32_t i=0; i<_bucketsToTest; ++i) {
+ document::BucketId bucket(16, i);
+ std::vector<uint16_t> nodes;
+ ClusterState clusterState(_state);
+ _distribution->getIdealNodes(
+ *_nodeType, clusterState, bucket, nodes,
+ _upStates, _redundancy);
+ for (uint32_t j=0; j<nodes.size(); ++j) {
+ ++result[nodes[j]];
+ }
+ }
+ return result;
+ }
+ std::vector<uint16_t> getDiskCounts(uint16_t node) const {
+ std::vector<uint16_t> result(3, 0);
+ for (uint32_t i=0; i<_bucketsToTest; ++i) {
+ document::BucketId bucket(16, i);
+ std::vector<uint16_t> nodes;
+ ClusterState clusterState(_state);
+ _distribution->getIdealNodes(
+ *_nodeType, clusterState, bucket, nodes,
+ _upStates, _redundancy);
+ for (uint32_t j=0; j<nodes.size(); ++j) {
+ if (nodes[j] == node) {
+ const NodeState& nodeState(clusterState.getNodeState(
+ Node(NodeType::STORAGE, node)));
+ // If disk was down, bucket should not map to this
+ // node at all
+ uint16_t disk = _distribution->getIdealDisk(
+ nodeState, node, bucket,
+ Distribution::IDEAL_DISK_EVEN_IF_DOWN);
+ ++result[disk];
+ }
+ }
+ }
+ return result;
+ }
+ };
+
+ std::vector<uint16_t> createNodeCountList(const std::string& source,
+ std::vector<uint16_t>& vals) {
+ std::vector<uint16_t> result(vals.size(), 0);
+ vespalib::StringTokenizer st(source, " ");
+ for (uint32_t i=0; i<st.size(); ++i) {
+ vespalib::StringTokenizer st2(st[i], ":");
+ uint16_t node(vespalib::lexical_cast<uint16_t>(st2[0]));
+ uint16_t value = vals[node];
+ if (st2[1] == std::string("*")) {
+ value = vals[node];
+ } else if (st2[1] == std::string("+")) {
+ if (vals[node] > 0) {
+ value = vals[node];
+ } else {
+ value = 0xffff;
+ }
+ } else {
+ value = vespalib::lexical_cast<uint16_t>(st2[1]);
+ }
+ result[node] = value;
+ }
+ return result;
+ }
+}
+
+#define ASSERT_BUCKET_NODE_COUNTS(test, result) \
+{ \
+ std::vector<uint16_t> cnt123(test.getNodeCounts()); \
+ std::vector<uint16_t> exp123(createNodeCountList(result, cnt123)); \
+ /*std::cerr << "Expected " << exp123 << " Got " << cnt123 << "\n";*/ \
+ CPPUNIT_ASSERT_EQUAL(exp123, cnt123); \
+}
+
+#define ASSERT_BUCKET_DISK_COUNTS(node, test, result) \
+{ \
+ std::vector<uint16_t> cnt123(test.getDiskCounts(node)); \
+ std::vector<uint16_t> exp123(createNodeCountList(result, cnt123)); \
+ CPPUNIT_ASSERT_EQUAL(exp123, cnt123); \
+}
+
+void
+DistributionTest::testDown()
+{
+ ASSERT_BUCKET_NODE_COUNTS(
+ Test().state("storage:10 .4.s:m .5.s:m .6.s:d .7.s:d .9.s:r")
+ .upStates("u"),
+ "0:+ 1:+ 2:+ 3:+ 8:+");
+
+ ASSERT_BUCKET_NODE_COUNTS(
+ Test().state("storage:10 .4.s:m .5.s:m .6.s:d .7.s:d .9.s:r")
+ .upStates("ur"),
+ "0:+ 1:+ 2:+ 3:+ 8:+ 9:+");
+}
+
+void
+DistributionTest::testDiskDown()
+{
+ ASSERT_BUCKET_DISK_COUNTS(
+ 2,
+ Test().state("storage:10 .2.d:3 .2.d.0:d"),
+ "1:+ 2:+");
+}
+
+void
+DistributionTest::testSerializeDeserialize()
+{
+ Test t1;
+ Test t2;
+ t2.distribution(new Distribution(t1._distribution->serialize()));
+ CPPUNIT_ASSERT_EQUAL(t1.getNodeCounts(), t2.getNodeCounts());
+}
+
+void
+DistributionTest::testDiskDownMaintenance()
+{
+ ASSERT_BUCKET_DISK_COUNTS(
+ 2,
+ Test().state("storage:10 .2.s:m .2.d:3 .2.d.0:d").upStates("um"),
+ "1:+ 2:+");
+}
+
+void
+DistributionTest::testInitializing()
+{
+ ASSERT_BUCKET_NODE_COUNTS(
+ Test().state("distributor:3 .0.s:i .1.s:i .2.s:i")
+ .upStates("ui")
+ .nodeType(NodeType::DISTRIBUTOR),
+ "0:+ 1:+ 2:+");
+}
+
+void
+DistributionTest::testHighSplitBit()
+{
+ // Only 3 nodes of 10 are up => all copies should end on the 3 nodes and
+ // none on the down nodes
+ ClusterState state("storage:100");
+
+ Distribution distr(Distribution::getDefaultDistributionConfig(3, 100));
+
+ std::ostringstream ost1;
+ std::ostringstream ost2;
+
+ for (uint32_t bits = 33; bits < 36; ++bits) {
+ uint64_t base = 0x23456789;
+ base |= (1 << bits);
+
+ document::BucketId bid1 = document::BucketId(bits, base);
+ document::BucketId bid2 = document::BucketId(bits, base);
+
+ std::vector<uint16_t> nodes1 =
+ distr.getIdealStorageNodes(state,
+ bid1,
+ "u");
+
+ std::vector<uint16_t> nodes2 =
+ distr.getIdealStorageNodes(state,
+ bid2,
+ "u");
+
+ ost1 << bid1 << " vs. " << bid2 << ": ";
+ ost2 << bid1 << " vs. " << bid2 << ": ";
+
+ for (uint32_t i = 0; i < nodes1.size(); ++i) {
+ ost1 << nodes1[i] << " ";
+ }
+ ost1 << "\n";
+
+ for (uint32_t i = 0; i < nodes2.size(); ++i) {
+ ost2 << nodes2[i] << " ";
+ }
+ ost2 << "\n";
+ }
+
+ CPPUNIT_ASSERT_EQUAL(ost1.str(), ost2.str());
+}
+
+
+
+void
+DistributionTest::testDiskCapacityWeights()
+{
+ uint16_t num_disks = 10;
+ std::vector<double> capacities(num_disks);
+
+ RandomGen rg(13);
+ std::ostringstream ost;
+ ost << "d:" << num_disks;
+ for (unsigned i = 0; i < num_disks; ++i) {
+ capacities[i] = rg.nextDouble();
+ ost << " d." << i << ".c:" << capacities[i];
+ }
+
+ NodeState nodeState(ost.str(), &NodeType::STORAGE);
+
+ Distribution distr(Distribution::getDefaultDistributionConfig(2, 3));
+
+ for(int j=0; j < 10; ++j) {
+ std::vector<float> diskDist(num_disks);
+ for(int i=0; i < 1000; ++i) {
+ document::BucketId id(16, i);
+ int index = distr.getPreferredAvailableDisk(nodeState, j, id);
+ diskDist[index]+=1;
+ }
+
+ //normalization
+ for (unsigned i = 0; i < num_disks; ++i) {
+ diskDist[i] /= capacities[i];
+ }
+
+ std::sort(diskDist.begin(), diskDist.end());
+
+ double avg=0.0;
+ for (unsigned i = 0; i < num_disks; ++i) {
+ avg+=diskDist[i];
+ }
+ avg /= num_disks;
+
+ double skew = (diskDist[num_disks-1]-avg)/(diskDist[num_disks-1]);
+
+ CPPUNIT_ASSERT(skew < 0.3);
+ }
+}
+
+
+void
+DistributionTest::testDiskSkewLocal()
+{
+ Distribution distr(Distribution::getDefaultDistributionConfig(
+ 2, 3, vespa::config::content::StorDistributionConfig::MODULO_INDEX));
+ std::vector<float> diskDist(100);
+ NodeState nodeState;
+ nodeState.setDiskCount(100);
+ for(int i=0; i < 65536; i++) {
+ document::BucketId id(16, i);
+ int index = distr.getPreferredAvailableDisk(nodeState, 7, id);
+ diskDist[index]+=1;
+ }
+
+ std::sort(diskDist.begin(), diskDist.end());
+
+ CPPUNIT_ASSERT((diskDist[99]-diskDist[0])/(diskDist[99]) < 0.05);
+
+}
+
+
+
+void
+DistributionTest::testDiskSkewGlobal()
+{
+ uint16_t num_disks = 10;
+ uint16_t num_nodes = 10;
+ Distribution distr(Distribution::getDefaultDistributionConfig(
+ 2, num_nodes, vespa::config::content::StorDistributionConfig::MODULO_INDEX));
+ std::vector<std::vector<float> > diskDist(
+ num_nodes, std::vector<float>(num_disks));
+ NodeState nodeState;
+ nodeState.setDiskCount(num_disks);
+ for(uint16_t idx=0; idx < num_nodes; idx++) {
+ for(int i=0; i < 1000; i++) {
+ document::BucketId id(16, i);
+ int diskIndex = distr.getPreferredAvailableDisk(nodeState, idx, id);
+ diskDist[idx][diskIndex]+=1;
+ }
+ }
+
+ std::vector<float> diskDist2;
+ for(uint16_t idx=0; idx < num_nodes; idx++) {
+ for(uint16_t d=0; d < num_disks; d++) {
+ diskDist2.push_back(diskDist[idx][d]);
+ }
+ }
+
+ std::sort(diskDist2.begin(), diskDist2.end());
+
+ double skew = (diskDist2[num_nodes*num_disks-1]-diskDist2[0])/(diskDist2[num_nodes*num_disks-1]);
+
+ CPPUNIT_ASSERT(skew < 0.2);
+
+}
+
+
+void
+DistributionTest::testDiskIntersection()
+{
+ uint16_t num_disks = 8;
+ uint16_t num_nodes = 20;
+ float max = 0;
+ Distribution distr(Distribution::getDefaultDistributionConfig(
+ 2, num_nodes, vespa::config::content::StorDistributionConfig::MODULO_INDEX));
+
+ NodeState nodeState;
+ nodeState.setDiskCount(num_disks);
+
+ for(uint16_t i=0; i < num_nodes-1; i++) {
+ for(uint16_t j=i+1; j < num_nodes; j++) {
+ uint64_t count =0;
+//std::cerr << "Comparing node " << i << " and node " << j << ":\n";
+ for(int b=0; b < 1000; b++) {
+ document::BucketId id(16, b);
+ int idxI = distr.getPreferredAvailableDisk(nodeState, i, id);
+ int idxJ = distr.getPreferredAvailableDisk(nodeState, j, id);
+//if (b < 50) std::cerr << " " << b << ": " << idxI << ", " << idxJ << "\n";
+ if(idxI == idxJ){
+ count++;
+ }
+ }
+ if(count > max){
+ max = count;
+ }
+ }
+ }
+ if (max / 1000 > 0.5) {
+ std::ostringstream ost;
+ ost << "Value of " << max << " / " << 1000 << " is more than 0.5";
+ CPPUNIT_FAIL(ost.str());
+ }
+}
+
+
+void
+DistributionTest::testSkew()
+{
+ const int buckets = 200000;
+ const int nodes = 50;
+ const size_t copies = 3;
+
+ ClusterState systemState("storage:50");
+
+ Distribution distr(
+ Distribution::getDefaultDistributionConfig(copies, nodes));
+
+ std::vector<std::pair<uint64_t, std::vector<uint16_t> > > _distribution(buckets);
+ std::vector<int> _nodeCount(nodes, 0);
+
+ FastOS_Time start;
+ start.SetNow();
+ for (int i = 0; i < buckets; i++) {
+ _distribution[i].first = i * 100;
+ _distribution[i].second = distr.getIdealStorageNodes(
+ systemState, document::BucketId(26, i * 100));
+ CPPUNIT_ASSERT_EQUAL(copies, _distribution[i].second.size());
+ sort(_distribution[i].second.begin(), _distribution[i].second.end());
+ unique(_distribution[i].second.begin(), _distribution[i].second.end());
+ CPPUNIT_ASSERT_EQUAL(copies, _distribution[i].second.size());
+
+ for (unsigned j = 0; j < _distribution[i].second.size(); j++) {
+ _nodeCount[_distribution[i].second[j]]++;
+ }
+ }
+
+/**
+ for (int i = 0; i < nodes; i++) {
+ fprintf(stderr, "%d ", _nodeCount[i]);
+ }
+
+ double elapsed = start.MilliSecsToNow();
+ fprintf(stderr, "%d calcs in %f ms = %f calcs/sec\n",
+ buckets, elapsed, double(buckets * 1000) / elapsed);
+*/
+ sort(_nodeCount.begin(), _nodeCount.end());
+
+/**
+ // Check distribution
+ for (int i = 0; i < nodes; i++) {
+ fprintf(stderr, "%d ", _nodeCount[i]);
+ }
+*/
+
+ double skew = _nodeCount[nodes - 1] - _nodeCount[0];
+ skew /= _nodeCount[nodes - 1];
+ // fprintf(stderr, " skew = %f\n", skew);
+ CPPUNIT_ASSERT_MESSAGE("Distribution skew too big (> 6%)", skew < 0.06);
+
+}
+
+// Get node with distribution farest from average
+int
+getMaxAbs(const std::vector<int> distribution, double avg, int start)
+{
+ int max = start;
+ for (uint32_t i = 0; i < distribution.size(); i++) {
+ if(fabs(distribution[i]-avg) > fabs(distribution[max]-avg))
+ max = i;
+ }
+ return max;
+}
+
+void
+getSkew(int n, std::vector<int> distribution, int &min, int &max, double &skew)
+{
+ min = 0;
+ max = 0;
+
+ for(int i=0; i<n; i++){
+ if(distribution[i] < distribution[min])
+ min = i;
+ if(distribution[i] > distribution[max])
+ max = i;
+ }
+
+ skew = distribution[max] - distribution[min];
+ skew /= distribution[max];
+}
+
+
+double
+get_K_lowest(std::vector<double> v, int k)
+{
+ double lowest[k];
+
+ for (int i = 0; i < k; i++){
+ lowest[i] = v[i];
+ }
+
+ for (uint32_t i = 0; i < v.size(); i++){
+ for (int j = 0; j < k; j++){
+ if( v[i] < lowest[j]){
+ for (int l = k-1; l > j; l--){
+ lowest[l] = lowest[l-1];
+ }
+ lowest[j] = v[i];
+ break;
+ }
+ }
+ }
+
+ return lowest[k-1];
+}
+
+void
+DistributionTest::testDistribution()
+{
+ const int min_buckets = 1024*64;
+ const int max_buckets = 1024*64;
+ const int min_nodes = 2;
+ const int max_nodes = 50;
+
+ FastOS_File file;
+ FastOS_File file_w;
+
+ for(int b=min_buckets; b<= max_buckets; b+=b){
+ std::ostringstream ostf;
+ std::ostringstream ostf_w;
+ std::ostringstream ostf_weights;
+
+ for(int n=min_nodes; n<= max_nodes; n++){
+
+ //Unweighted
+ std::ostringstream s1;
+ s1 << "storage:" << n << std::endl;
+ ClusterState systemState(s1.str());
+
+ Distribution distr(
+ Distribution::getDefaultDistributionConfig(3, n));
+
+ std::vector<std::pair<uint64_t, std::vector<uint16_t> > > _distribution(b);
+ std::vector<int> _nodeCount(n, 0);
+
+ for (int i = 0; i < b; i++) {
+ _distribution[i].first = i;
+ _distribution[i].second = distr.getIdealStorageNodes(
+ systemState, document::BucketId(26, i));
+ sort(_distribution[i].second.begin(), _distribution[i].second.end());
+ unique(_distribution[i].second.begin(), _distribution[i].second.end());
+
+ for (unsigned j = 0; j < _distribution[i].second.size(); j++) {
+ _nodeCount[_distribution[i].second[j]]++;
+ }
+ }
+
+ int min = 0;
+ int max = 0;
+ for(int i=0; i<n; i++){
+ if(_nodeCount[i] < _nodeCount[min])
+ min = i;
+ if(_nodeCount[i] > _nodeCount[max])
+ max = i;
+ }
+
+ double skew = _nodeCount[max] - _nodeCount[min];
+ skew /= _nodeCount[max];
+ fprintf(stderr, "%d \t skew = %f\n", n, skew);
+ CPPUNIT_ASSERT_MESSAGE("Distribution skew too big (> 10%)", skew < 0.1);
+ }
+ }
+}
+
+void
+DistributionTest::testSkewWithDown()
+{
+ const int buckets = 200000;
+ const int nodes = 50;
+ const size_t copies = 3;
+
+ ClusterState systemState("storage:50 .5.s:d .10.s:d .15.s:d .20.s:d "
+ ".25.s:d .30.s:d .35.s:d .40.s:d .45.s:d");
+
+ Distribution distr(Distribution::getDefaultDistributionConfig(3, 50));
+
+ std::vector<std::pair<uint64_t, std::vector<uint16_t> > > _distribution(buckets);
+ std::vector<int> _nodeCount(nodes, 0);
+
+ for (int i = 0; i < buckets; i++) {
+ _distribution[i].second.reserve(copies);
+ }
+
+ FastOS_Time start;
+ start.SetNow();
+ for (int i = 0; i < buckets; i++) {
+ _distribution[i].first = i * 100;
+ _distribution[i].second = distr.getIdealStorageNodes(
+ systemState, document::BucketId(26, _distribution[i].first));
+ CPPUNIT_ASSERT_EQUAL(copies, _distribution[i].second.size());
+ sort(_distribution[i].second.begin(), _distribution[i].second.end());
+ unique(_distribution[i].second.begin(), _distribution[i].second.end());
+ CPPUNIT_ASSERT_EQUAL(copies, _distribution[i].second.size());
+
+ for (unsigned j = 0; j < _distribution[i].second.size(); j++) {
+ _nodeCount[_distribution[i].second[j]]++;
+ }
+ }
+ /*
+ double elapsed = start.MilliSecsToNow();
+ fprintf(stderr, "%d calcs in %f ms = %f calcs/sec\n",
+ buckets, elapsed, double(buckets * 1000) / elapsed);
+
+ // Check distribution
+ for (int i = 0; i < nodes; i++) {
+ fprintf(stderr, "%d ", _nodeCount[i]);
+ }
+ */
+ sort(_nodeCount.begin(), _nodeCount.end());
+ int firstUp = 0;
+ while (_nodeCount[firstUp] == 0) {
+ firstUp++;
+ }
+ double skew = _nodeCount[nodes - 1] - _nodeCount[firstUp];
+ skew /= _nodeCount[nodes - 1];
+ //fprintf(stderr, " skew = %f\n", skew);
+ CPPUNIT_ASSERT_MESSAGE("Distribution skew too big (> 5%)", skew < 0.05);
+}
+
+void
+DistributionTest::testMove()
+{
+ // This test is quite fragile, it will break if the ideal state algorithm is
+ // changed in such a way that Bucket 0x8b4f67ae remains on node 0 and 1 if
+ // node 4 is added.
+ std::vector<uint16_t> res;
+ {
+ ClusterState systemState("storage:3");
+ document::BucketId bucket(16, 0x8b4f67ae);
+
+ Distribution distr(Distribution::getDefaultDistributionConfig(2, 3));
+
+ res = distr.getIdealStorageNodes(systemState, bucket);
+ CPPUNIT_ASSERT_EQUAL(size_t(2), res.size());
+ }
+
+ std::vector<uint16_t> res2;
+ {
+ ClusterState systemState("storage:4");
+
+ Distribution distr(Distribution::getDefaultDistributionConfig(2, 4));
+
+ document::BucketId bucket(16, 0x8b4f67ae);
+
+ res2 = distr.getIdealStorageNodes(systemState, bucket);
+ CPPUNIT_ASSERT_EQUAL(size_t(2), res2.size());
+ }
+
+ sort(res.begin(), res.end());
+ sort(res2.begin(), res2.end());
+
+ std::vector<uint16_t> diff(2);
+ std::vector<uint16_t>::iterator it;
+
+ it=set_difference(res.begin(), res.end(), res2.begin(), res2.end(), diff.begin());
+ CPPUNIT_ASSERT_EQUAL(1, int(it-diff.begin()));
+
+}
+
+void
+DistributionTest::testMoveConstraints()
+{
+ ClusterState systemState("storage:10");
+
+ Distribution distr(Distribution::getDefaultDistributionConfig(3, 12));
+
+ std::vector<std::vector<uint16_t> > initBuckets(10000);
+ for (unsigned i = 0; i < initBuckets.size(); i++) {
+ initBuckets[i] = distr.getIdealStorageNodes(
+ systemState, document::BucketId(16, i));
+ sort(initBuckets[i].begin(), initBuckets[i].end());
+ }
+
+ {
+ // Check that adding a down node has no effect
+ std::vector<std::vector<uint16_t> > addedDownBuckets(10000);
+ systemState = ClusterState("storage:11 .10.s:d");
+
+ for (unsigned i = 0; i < addedDownBuckets.size(); i++) {
+ addedDownBuckets[i] = distr.getIdealStorageNodes(
+ systemState, document::BucketId(16, i));
+ sort(addedDownBuckets[i].begin(), addedDownBuckets[i].end());
+ }
+ for (unsigned i = 0; i < initBuckets.size(); i++) {
+ if (initBuckets[i] != addedDownBuckets[i]) {
+ std::cerr << i << ": ";
+ std::copy(initBuckets[i].begin(), initBuckets[i].end(), std::ostream_iterator<uint32_t>(std::cerr, ","));
+ std::cerr << " -> ";
+ std::copy(addedDownBuckets[i].begin(), addedDownBuckets[i].end(), std::ostream_iterator<uint32_t>(std::cerr, ","));
+ std::cerr << std::endl;
+
+ }
+ CPPUNIT_ASSERT(initBuckets[i] == addedDownBuckets[i]);
+ }
+ }
+
+ {
+ // Check that if we disable one node, we're not moving stuff away from
+ // any other node
+ std::vector<std::vector<uint16_t> > removed0Buckets(10000);
+ systemState = ClusterState("storage:10 .0.s:d");
+
+ for (unsigned i = 0; i < removed0Buckets.size(); i++) {
+ removed0Buckets[i] = distr.getIdealStorageNodes(
+ systemState, document::BucketId(16, i));
+ sort(removed0Buckets[i].begin(), removed0Buckets[i].end());
+ }
+ for (unsigned i = 0; i < initBuckets.size(); i++) {
+ std::vector<uint16_t> movedAway;
+ set_difference(initBuckets[i].begin(), initBuckets[i].end(),
+ removed0Buckets[i].begin(), removed0Buckets[i].end(),
+ back_inserter(movedAway));
+ if (movedAway.size() > 0) {
+ if (movedAway[0] != 0) {
+ std::cerr << i << ": ";
+ copy(initBuckets[i].begin(), initBuckets[i].end(), std::ostream_iterator<uint32_t>(std::cerr, ","));
+ std::cerr << " -> ";
+ copy(removed0Buckets[i].begin(), removed0Buckets[i].end(), std::ostream_iterator<uint32_t>(std::cerr, ","));
+ std::cerr << std::endl;
+ }
+
+ CPPUNIT_ASSERT_EQUAL((size_t)1, movedAway.size());
+ CPPUNIT_ASSERT_EQUAL((uint16_t)0u, movedAway[0]);
+ }
+ }
+ }
+
+ {
+ // Check that if we're adding one node, we're not moving stuff to any
+ // other node
+ std::vector<std::vector<uint16_t> > added10Buckets(10000);
+ systemState = ClusterState("storage:11");
+
+ for (unsigned i = 0; i < added10Buckets.size(); i++) {
+ added10Buckets[i] = distr.getIdealStorageNodes(
+ systemState, document::BucketId(16, i));
+ sort(added10Buckets[i].begin(), added10Buckets[i].end());
+ }
+ for (unsigned i = 0; i < initBuckets.size(); i++) {
+ std::vector<uint16_t> movedInto;
+ std::set_difference(added10Buckets[i].begin(), added10Buckets[i].end(),
+ initBuckets[i].begin(), initBuckets[i].end(),
+ std::inserter(movedInto, movedInto.begin()));
+ if (movedInto.size() > 0) {
+ CPPUNIT_ASSERT_EQUAL((size_t)1, movedInto.size());
+ CPPUNIT_ASSERT_EQUAL((uint16_t)10, movedInto[0]);
+ }
+ }
+ }
+}
+
+void
+DistributionTest::testDistributionBits()
+{
+ ClusterState state1("bits:16 distributor:10");
+ ClusterState state2("bits:19 distributor:10");
+
+ Distribution distr(Distribution::getDefaultDistributionConfig(1, 10));
+
+ std::ostringstream ost1;
+ std::ostringstream ost2;
+
+ for (unsigned i = 0; i < 100; i++) {
+ int val = rand();
+ uint32_t index = distr.getIdealDistributorNode(
+ state1, document::BucketId(19, val), "u");
+ ost1 << index << " ";
+ index = distr.getIdealDistributorNode(
+ state2, document::BucketId(19, val), "u");
+ ost2 << index << " ";
+ }
+
+ CPPUNIT_ASSERT(ost1.str() != ost2.str());
+}
+
+void
+DistributionTest::testRedundancyHierarchicalDistribution()
+{
+ ClusterState state("storage:10 distributor:10");
+
+ Distribution distr1(Distribution::getDefaultDistributionConfig(1, 10));
+ Distribution distr2(Distribution::getDefaultDistributionConfig(2, 10));
+
+ for (unsigned i = 0; i < 100; i++) {
+ uint16_t d1 = distr1.getIdealDistributorNode(
+ state, document::BucketId(16, i), "u");
+ uint16_t d2 = distr2.getIdealDistributorNode(
+ state, document::BucketId(16, i), "u");
+ CPPUNIT_ASSERT_EQUAL(d1, d2);
+ }
+}
+/*
+void
+DistributionTest::testHierarchicalDistributionPerformance()
+{
+ std::ostringstream ost;
+ ost << "redundancy 2\n"
+ "group[62]\n"
+ "group[0].name mycluster\n"
+ "group[0].index 0\n"
+ "group[0].partitions *\n"
+ "group[0].nodes[0]\n";
+
+ for (uint32_t i = 0; i < 21; ++i) {
+ int idx = (i * 3) + 1;
+
+ ost << "group[" << idx << "].name rack" << i << "\n"
+ << "group[" << idx << "].index 0." << i << "\n"
+ << "group[" << idx << "].partitions 1|*\n"
+ << "group[" << idx << "].nodes[0]\n";
+
+ for (uint32_t j = 0; j < 2; ++j) {
+ idx++;
+
+ ost << "group[" << idx << "].name switch" << idx << "\n"
+ << "group[" << idx << "].index 0." << i << "." << j << "\n"
+ << "group[" << idx << "].partitions 1|*\n"
+ << "group[" << idx << "].nodes[50]\n";
+
+ for (uint32_t n = 0; n < 50; ++n) {
+ int nIdx = (i * 100 + j * 50 + n);
+ ost << "group[" << idx << "].nodes[" << n << "].index " << nIdx << "\n";
+ }
+ }
+ }
+
+ std::cerr << ost.str() << "\n";
+
+ Distribution distr(vespa::config::content::StorDistributionConfig(
+ vespalib::StringTokenizer(ost.str(), "\n", "").getTokens()));
+ ClusterState state("distributor:2100 storage:2100");
+
+ uint32_t timeNow = time(NULL);
+ uint32_t numBuckets = 1000000;
+
+ std::vector<uint16_t> nodes;
+ for (uint32_t i = 0; i < numBuckets; i++) {
+ nodes = distr.getIdealStorageNodes(
+ state, document::BucketId(16, i), "u");
+ }
+
+ uint32_t timeSpent = time(NULL) - timeNow;
+ std::cerr << "Did " << numBuckets << " in " << timeSpent << " seconds. (" << ((double)numBuckets / (double)timeSpent) << " ops/sec)\n";
+}
+*/
+
+void
+DistributionTest::testHierarchicalDistribution()
+{
+ std::string distConfig(
+ "redundancy 4\n"
+ "group[3]\n"
+ "group[0].name \"invalid\"\n"
+ "group[0].index \"invalid\"\n"
+ "group[0].partitions 2|*\n"
+ "group[0].nodes[0]\n"
+ "group[1].name rack0\n"
+ "group[1].index 0\n"
+ "group[1].nodes[3]\n"
+ "group[1].nodes[0].index 0\n"
+ "group[1].nodes[1].index 1\n"
+ "group[1].nodes[2].index 2\n"
+ "group[2].name rack1\n"
+ "group[2].index 1\n"
+ "group[2].nodes[3]\n"
+ "group[2].nodes[0].index 3\n"
+ "group[2].nodes[1].index 4\n"
+ "group[2].nodes[2].index 5\n");
+ Distribution distr(distConfig);
+ ClusterState state("distributor:6 storage:6");
+
+ for (uint32_t i = 0; i < 3; ++i) {
+ CPPUNIT_ASSERT_EQUAL(
+ vespalib::string("rack0"),
+ distr.getNodeGraph().getGroupForNode(i)->getName());
+ }
+ for (uint32_t i = 3; i < 6; ++i) {
+ CPPUNIT_ASSERT_EQUAL(
+ vespalib::string("rack1"),
+ distr.getNodeGraph().getGroupForNode(i)->getName());
+ }
+
+ std::vector<int> mainNode(6);
+ for (uint32_t i=0; i<100; ++i) {
+ std::vector<uint16_t> nodes = distr.getIdealStorageNodes(
+ state, document::BucketId(16, i), "u");
+ CPPUNIT_ASSERT_EQUAL((size_t) 4, nodes.size());
+ CPPUNIT_ASSERT(nodes[0] < mainNode.size());
+ ++mainNode[nodes[0]];
+ }
+ std::vector<int> expectedMains(6);
+ expectedMains[0] = 9;
+ expectedMains[1] = 21;
+ expectedMains[2] = 18;
+ expectedMains[3] = 16;
+ expectedMains[4] = 16;
+ expectedMains[5] = 20;
+ CPPUNIT_ASSERT_EQUAL(expectedMains, mainNode);
+}
+
+void
+DistributionTest::testGroupCapacity()
+{
+ std::string distConfig(
+ "redundancy 1\n"
+ "group[3]\n"
+ "group[0].name \"invalid\"\n"
+ "group[0].index \"invalid\"\n"
+ "group[0].partitions *\n"
+ "group[0].nodes[0]\n"
+ "group[1].name rack0\n"
+ "group[1].index 0\n"
+ "group[1].capacity 1.0\n"
+ "group[1].nodes[3]\n"
+ "group[1].nodes[0].index 0\n"
+ "group[1].nodes[1].index 1\n"
+ "group[1].nodes[2].index 2\n"
+ "group[2].name rack1\n"
+ "group[2].index 1\n"
+ "group[2].capacity 4.0\n"
+ "group[2].nodes[3]\n"
+ "group[2].nodes[0].index 3\n"
+ "group[2].nodes[1].index 4\n"
+ "group[2].nodes[2].index 5\n");
+ Distribution distr(distConfig);
+ ClusterState state("distributor:6 storage:6");
+
+ int group0count = 0;
+ int group1count = 0;
+ for (uint32_t i = 0; i < 1000; i++) {
+ std::vector<uint16_t> nodes = distr.getIdealStorageNodes(
+ state, document::BucketId(16, i), "u");
+ if (nodes[0] == 0 || nodes[0] == 1 || nodes[0] == 2) {
+ group0count++;
+ }
+ if (nodes[0] == 3 || nodes[0] == 4 || nodes[0] == 5) {
+ group1count++;
+ }
+ }
+
+ //std::cerr << "Group 0 is " << group0count << " 1 is " << group1count << "\n";
+
+ CPPUNIT_ASSERT(group0count > 180 && group0count < 220);
+ CPPUNIT_ASSERT_EQUAL(1000 - group0count, group1count);
+}
+
+void
+DistributionTest::testHierarchicalNoRedistribution()
+{
+ std::string distConfig(
+ "redundancy 2\n"
+ "group[5]\n"
+ "group[0].name \"invalid\"\n"
+ "group[0].index \"invalid\"\n"
+ "group[0].partitions *|*\n"
+ "group[0].nodes[0]\n"
+ "group[1].name switch0\n"
+ "group[1].index 0\n"
+ "group[1].partitions 1|*\n"
+ "group[1].nodes[0]\n"
+ "group[2].name rack0\n"
+ "group[2].index 0.0\n"
+ "group[2].nodes[1]\n"
+ "group[2].nodes[0].index 0\n"
+ "group[3].name rack1\n"
+ "group[3].index 0.1\n"
+ "group[3].nodes[1]\n"
+ "group[3].nodes[0].index 1\n"
+ "group[4].name switch0\n"
+ "group[4].index 1\n"
+ "group[4].partitions *\n"
+ "group[4].nodes[0]\n"
+ "group[5].name rack0\n"
+ "group[5].index 1.0\n"
+ "group[5].nodes[1]\n"
+ "group[5].nodes[0].index 2\n"
+ "group[6].name rack1\n"
+ "group[6].index 1.1\n"
+ "group[6].nodes[1]\n"
+ "group[6].nodes[0].index 3\n");
+ Distribution distribution(distConfig);
+
+ ClusterState state("version:12 storage:4 distributor:4");
+
+ std::vector<uint16_t> nodes;
+ std::vector< std::vector<uint16_t> > distr(4);
+ int numBuckets = 1000;
+
+ for (int i = 0; i < numBuckets; i++) {
+ nodes = distribution.getIdealStorageNodes(
+ state, document::BucketId(16, i), "u");
+ for (uint16_t j=0; j<nodes.size(); ++j) {
+ distr[nodes[j]].push_back(i);
+ }
+ nodes.clear();
+ }
+
+ std::vector<uint16_t>::iterator it;
+ std::vector<uint16_t> v(1000);
+
+ it=set_intersection (distr[0].begin(), distr[0].end(), distr[1].begin(), distr[1].end(), v.begin());
+ CPPUNIT_ASSERT_EQUAL(0, int(it-v.begin()));
+ v.clear();
+
+ it=set_intersection (distr[2].begin(), distr[2].end(), distr[3].begin(), distr[3].end(), v.begin());
+ CPPUNIT_ASSERT_EQUAL(0, int(it-v.begin()));
+ v.clear();
+
+ it=set_union (distr[0].begin(), distr[0].end(), distr[1].begin(), distr[1].end(), v.begin());
+ CPPUNIT_ASSERT_EQUAL(numBuckets, int(it-v.begin()));
+ v.clear();
+
+ it=set_union (distr[2].begin(), distr[2].end(), distr[3].begin(), distr[3].end(), v.begin());
+ CPPUNIT_ASSERT_EQUAL(numBuckets, int(it-v.begin()));
+ v.clear();
+
+ state.setNodeState(Node(NodeType::STORAGE, 0),
+ NodeState(NodeType::STORAGE, State::DOWN));
+
+ std::vector< std::vector<uint16_t> > distr2(4);
+
+ for (int i = 0; i < numBuckets; i++) {
+ nodes = distribution.getIdealStorageNodes(
+ state, document::BucketId(16, i), "u");
+ for (uint16_t j=0; j<nodes.size(); ++j) {
+ CPPUNIT_ASSERT(0 != nodes[j]);
+ distr2[nodes[j]].push_back(i);
+ }
+ nodes.clear();
+ }
+
+ CPPUNIT_ASSERT_EQUAL((size_t)0, distr2[0].size());
+ v.clear();
+
+ it=set_difference (distr[1].begin(), distr[1].end(), distr2[1].begin(), distr2[1].end(), v.begin());
+ CPPUNIT_ASSERT_EQUAL(0, int(it-v.begin()));
+ v.clear();
+
+ it=set_difference (distr[2].begin(), distr[2].end(), distr2[2].begin(), distr2[2].end(), v.begin());
+ CPPUNIT_ASSERT_EQUAL(0, int(it-v.begin()));
+ v.clear();
+
+ it=set_difference (distr[3].begin(), distr[3].end(), distr2[3].begin(), distr2[3].end(), v.begin());
+ CPPUNIT_ASSERT_EQUAL(0, int(it-v.begin()));
+ v.clear();
+
+ state = ClusterState(
+ "distributor:5 .0.s:d storage:5 .0.s:d .1.s:d .1.m:foo\\x20bar");
+ std::ostringstream ost;
+ state.printStateGroupwise(ost, distribution, true, "");
+ CPPUNIT_ASSERT_EQUAL(std::string("\n"
+ "ClusterState(Version: 0, Cluster state: Up, Distribution bits: 16) {\n"
+ " Top group. 2 branches with distribution *|* {\n"
+ " Group 0: switch0. 2 branches with distribution 1|* {\n"
+ " Group 0: rack0. 1 node [0] {\n"
+ " distributor.0: Down\n"
+ " storage.0: Down\n"
+ " }\n"
+ " Group 1: rack1. 1 node [1] {\n"
+ " storage.1: Down: foo bar\n"
+ " }\n"
+ " }\n"
+ " Group 1: switch0. 2 branches with distribution * {\n"
+ " Group 0: rack0. 1 node [2] {\n"
+ " All nodes in group up and available.\n"
+ " }\n"
+ " Group 1: rack1. 1 node [3] {\n"
+ " All nodes in group up and available.\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ "}"), "\n" + ost.str());
+}
+
+namespace {
+ std::string groupConfig("group[3]\n"
+ "group[0].name \"invalid\"\n"
+ "group[0].index \"invalid\"\n"
+ "group[0].partitions 2|*\n"
+ "group[0].nodes[0]\n"
+ "group[1].name rack0\n"
+ "group[1].index 0\n"
+ "group[1].nodes[3]\n"
+ "group[1].nodes[0].index 0\n"
+ "group[1].nodes[1].index 1\n"
+ "group[1].nodes[2].index 2\n"
+ "group[2].name rack1\n"
+ "group[2].index 1\n"
+ "group[2].nodes[3]\n"
+ "group[2].nodes[0].index 3\n"
+ "group[2].nodes[1].index 4\n"
+ "group[2].nodes[2].index 5\n");
+}
+
+void
+DistributionTest::testActivePerGroup()
+{
+ typedef Distribution::IndexList IndexList;
+ // Disabled feature
+ {
+ Distribution distr("redundancy 4\n" + groupConfig);
+ CPPUNIT_ASSERT_EQUAL(false, distr.activePerGroup());
+ }
+ // All nodes split
+ {
+ Distribution distr("redundancy 4\n"
+ "active_per_leaf_group true\n" + groupConfig);
+ IndexList global;
+ global.push_back(0);
+ global.push_back(1);
+ global.push_back(2);
+ global.push_back(3);
+ global.push_back(4);
+ global.push_back(5);
+ std::vector<IndexList> actual(distr.splitNodesIntoLeafGroups(global));
+ std::vector<IndexList> expected;
+ expected.push_back(IndexList());
+ expected.push_back(IndexList());
+ expected[0].push_back(0);
+ expected[0].push_back(1);
+ expected[0].push_back(2);
+ expected[1].push_back(3);
+ expected[1].push_back(4);
+ expected[1].push_back(5);
+ CPPUNIT_ASSERT_EQUAL(expected, actual);
+ }
+ // Only nodes in one group
+ {
+ Distribution distr("redundancy 4\n"
+ "active_per_leaf_group true\n" + groupConfig);
+ IndexList global;
+ global.push_back(0);
+ global.push_back(1);
+ global.push_back(2);
+ std::vector<IndexList> actual(distr.splitNodesIntoLeafGroups(global));
+ std::vector<IndexList> expected;
+ expected.push_back(IndexList());
+ expected[0].push_back(0);
+ expected[0].push_back(1);
+ expected[0].push_back(2);
+ CPPUNIT_ASSERT_EQUAL(expected, actual);
+ }
+ // No nodes
+ {
+ Distribution distr("redundancy 4\n"
+ "active_per_leaf_group true\n" + groupConfig);
+ IndexList global;
+ std::vector<IndexList> actual(distr.splitNodesIntoLeafGroups(global));
+ std::vector<IndexList> expected;
+ CPPUNIT_ASSERT_EQUAL(expected, actual);
+ }
+ // Random nodes
+ {
+ Distribution distr("redundancy 4\n"
+ "active_per_leaf_group true\n" + groupConfig);
+ IndexList global;
+ global.push_back(5);
+ global.push_back(1);
+ global.push_back(3);
+ std::vector<IndexList> actual(distr.splitNodesIntoLeafGroups(global));
+ std::vector<IndexList> expected;
+ expected.push_back(IndexList());
+ expected.push_back(IndexList());
+ expected[0].push_back(1);
+ expected[1].push_back(5);
+ expected[1].push_back(3);
+ CPPUNIT_ASSERT_EQUAL(expected, actual);
+ }
+}
+
+void
+DistributionTest::testHierarchicalDistributeLessThanRedundancy()
+{
+ using namespace boost::assign;
+ Distribution distr("redundancy 4\n"
+ "active_per_leaf_group true\n" + groupConfig);
+ ClusterState state("storage:6");
+ std::vector<uint16_t> actual;
+
+ {
+ distr.getIdealNodes(NodeType::STORAGE, state, document::BucketId(16, 0),
+ actual, "uim", 4);
+ std::vector<uint16_t> expected;
+ expected += 3, 5, 1, 2;
+ CPPUNIT_ASSERT_EQUAL(expected, actual);
+ }
+ {
+ distr.getIdealNodes(NodeType::STORAGE, state, document::BucketId(16, 0),
+ actual, "uim", 3);
+ std::vector<uint16_t> expected;
+ expected += 3, 5, 1;
+ CPPUNIT_ASSERT_EQUAL(expected, actual);
+ }
+ {
+ distr.getIdealNodes(NodeType::STORAGE, state, document::BucketId(16, 0),
+ actual, "uim", 2);
+ std::vector<uint16_t> expected;
+ expected += 3, 1;
+ CPPUNIT_ASSERT_EQUAL(expected, actual);
+ }
+ {
+ distr.getIdealNodes(NodeType::STORAGE, state, document::BucketId(16, 0),
+ actual, "uim", 1);
+ std::vector<uint16_t> expected;
+ expected += 3;
+ CPPUNIT_ASSERT_EQUAL(expected, actual);
+ }
+}
+
+void
+DistributionTest::testEmptyAndCopy()
+{
+ Distribution d;
+ CPPUNIT_ASSERT(d.getNodeGraph().isLeafGroup());
+ CPPUNIT_ASSERT_EQUAL(uint16_t(0), d.getRedundancy());
+ CPPUNIT_ASSERT_EQUAL(uint16_t(0), d.getReadyCopies());
+ Distribution d2(d.serialize());
+ CPPUNIT_ASSERT_EQUAL(uint16_t(0), d2.getRedundancy());
+ CPPUNIT_ASSERT_EQUAL(uint16_t(0), d2.getReadyCopies());
+ Distribution d3(Distribution::getDefaultDistributionConfig());
+ d = d3;
+ CPPUNIT_ASSERT_EQUAL(uint16_t(2), d.getRedundancy());
+ CPPUNIT_ASSERT_EQUAL(uint16_t(1), d.getReadyCopies());
+}
+
+} // lib
+} // storage
diff --git a/vdslib/src/tests/distribution/grouptest.cpp b/vdslib/src/tests/distribution/grouptest.cpp
new file mode 100644
index 00000000000..828a00ff7d0
--- /dev/null
+++ b/vdslib/src/tests/distribution/grouptest.cpp
@@ -0,0 +1,90 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/fastos/fastos.h>
+#include <vespa/vdslib/distribution/group.h>
+
+#include <boost/assign.hpp>
+#include <vespa/vespalib/text/stringtokenizer.h>
+#include <vespa/vdstestlib/cppunit/macros.h>
+
+namespace storage {
+namespace lib {
+
+struct GroupTest : public CppUnit::TestFixture {
+ void testConfigHash();
+ void configHashUsesOriginalInputOrdering();
+ void configHashSubgroupsAreOrderedByGroupIndex();
+
+ CPPUNIT_TEST_SUITE(GroupTest);
+ CPPUNIT_TEST(testConfigHash);
+ CPPUNIT_TEST(configHashUsesOriginalInputOrdering);
+ CPPUNIT_TEST(configHashSubgroupsAreOrderedByGroupIndex);
+ CPPUNIT_TEST_SUITE_END();
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(GroupTest);
+
+namespace {
+ Group::UP createLeafGroup(uint16_t index, const std::string& name,
+ double capacity, const std::string& nodelist)
+ {
+ Group::UP group(new Group(index, name));
+ group->setCapacity(capacity);
+ vespalib::StringTokenizer st(nodelist, ",");
+ std::vector<uint16_t> nodes(st.size());
+ for (uint32_t i=0; i<st.size(); ++i) {
+ nodes[i] = atoi(st[i].c_str());
+ }
+ group->setNodes(nodes);
+ return group;
+ }
+}
+
+void
+GroupTest::testConfigHash()
+{
+ Group rootGroup(12, "foo", Group::Distribution("1|*"), 3);
+ rootGroup.addSubGroup(createLeafGroup(4, "bar", 1.5, "1,4,6,8"));
+ rootGroup.addSubGroup(createLeafGroup(6, "ror", 1.2, "3,10,11"));
+ rootGroup.addSubGroup(createLeafGroup(15, "ing", 1.0, "13,15"));
+
+ vespalib::string expected = "(12d1|*(4c1.5;1;4;6;8)(6c1.2;3;10;11)(15;13;15))";
+ CPPUNIT_ASSERT_EQUAL(expected, rootGroup.getDistributionConfigHash());
+}
+
+/**
+ * To maintain backwards compatibility, distribution config hashes must be
+ * output with the same node order as the groups were configured with, even
+ * if their internal node list has a well-defined ordering.
+ */
+void
+GroupTest::configHashUsesOriginalInputOrdering()
+{
+ Group rootGroup(1, "root", Group::Distribution("1|*"), 2);
+ rootGroup.addSubGroup(createLeafGroup(2, "fluffy", 1.0, "5,2,7,6"));
+ rootGroup.addSubGroup(createLeafGroup(3, "bunny", 1.0, "15,10,12,11"));
+
+ vespalib::string expected = "(1d1|*(2;5;2;7;6)(3;15;10;12;11))";
+ CPPUNIT_ASSERT_EQUAL(expected, rootGroup.getDistributionConfigHash());
+}
+
+/**
+ * Unlike node indices, groups have always been output in ascending order in
+ * the config hash, and we must ensure this remains the case.
+ *
+ * Who said anything about internal consistency, anyway?
+ */
+void
+GroupTest::configHashSubgroupsAreOrderedByGroupIndex()
+{
+ Group rootGroup(1, "root", Group::Distribution("1|*"), 2);
+ rootGroup.addSubGroup(createLeafGroup(5, "fluffy", 1.0, "5,2,7,6"));
+ rootGroup.addSubGroup(createLeafGroup(3, "bunny", 1.0, "15,10,12,11"));
+ rootGroup.addSubGroup(createLeafGroup(4, "kitten", 1.0, "3,4,8"));
+
+ vespalib::string expected = "(1d1|*(3;15;10;12;11)(4;3;4;8)(5;5;2;7;6))";
+ CPPUNIT_ASSERT_EQUAL(expected, rootGroup.getDistributionConfigHash());
+}
+
+} // lib
+} // storage
diff --git a/vdslib/src/tests/distribution/idealnodecalculatorcachetest.cpp b/vdslib/src/tests/distribution/idealnodecalculatorcachetest.cpp
new file mode 100644
index 00000000000..8195d6dd070
--- /dev/null
+++ b/vdslib/src/tests/distribution/idealnodecalculatorcachetest.cpp
@@ -0,0 +1,331 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/vdslib/distribution/idealnodecalculatorcache.h>
+#include <vespa/vdslib/distribution/idealnodecalculatorimpl.h>
+#include <vespa/vdstestlib/cppunit/macros.h>
+
+namespace storage {
+namespace lib {
+
+struct IdealNodeCalculatorCacheTest : public CppUnit::TestFixture {
+
+ /** Test that you get a correct result forwarded through simple. */
+ void testSimple();
+ /** Test that similar buckets use different cache slots. */
+ void testLocalityCached();
+ /** Test that buckets using same cache slot invalidates each other. */
+ void testBucketsSameCacheSlot();
+ /** Test that cache is invalidated on changes. */
+ void testCacheInvalidationOnChanges();
+ /** Test that values for different upstates are kept for themselves. */
+ void testDifferentUpStates();
+ /** Test that values for different node types are kept for themselves. */
+ void testDifferentNodeTypes();
+ /**
+ * Do a performance test, verifying that cache actually significantly
+ * increase performance.
+ */
+ void testPerformance();
+
+ CPPUNIT_TEST_SUITE(IdealNodeCalculatorCacheTest);
+ CPPUNIT_TEST(testSimple);
+ CPPUNIT_TEST(testLocalityCached);
+ CPPUNIT_TEST(testBucketsSameCacheSlot);
+ CPPUNIT_TEST(testCacheInvalidationOnChanges);
+ CPPUNIT_TEST(testDifferentUpStates);
+ CPPUNIT_TEST(testDifferentNodeTypes);
+ CPPUNIT_TEST(testPerformance);
+ CPPUNIT_TEST_SUITE_END();
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(IdealNodeCalculatorCacheTest);
+
+void
+IdealNodeCalculatorCacheTest::testSimple()
+{
+ ClusterState state("storage:10");
+ Distribution distr(Distribution::getDefaultDistributionConfig(3, 10));
+ IdealNodeCalculatorImpl::SP impl(new IdealNodeCalculatorImpl);
+ IdealNodeCalculatorCache cache(impl, 4);
+
+ IdealNodeCalculatorConfigurable& configurable(cache);
+ IdealNodeCalculator& calc(cache);
+ configurable.setDistribution(distr);
+ configurable.setClusterState(state);
+
+ std::string expected("[storage.8, storage.9, storage.6]");
+ CPPUNIT_ASSERT_EQUAL(
+ expected,
+ calc.getIdealStorageNodes(document::BucketId(16, 5)).toString());
+}
+
+void
+IdealNodeCalculatorCacheTest::testLocalityCached()
+{
+ ClusterState state("bits:6 storage:10");
+ Distribution distr(Distribution::getDefaultDistributionConfig(3, 10));
+ IdealNodeCalculatorImpl::SP impl(new IdealNodeCalculatorImpl);
+ IdealNodeCalculatorCache cache(impl, 1024);
+
+ IdealNodeCalculatorConfigurable& configurable(cache);
+ IdealNodeCalculator& calc(cache);
+ configurable.setDistribution(distr);
+ configurable.setClusterState(state);
+
+ std::vector<document::BucketId> local;
+ local.push_back(document::BucketId(15, 134));
+ local.push_back(document::BucketId(16, 134));
+ local.push_back(document::BucketId(17, 134));
+ local.push_back(document::BucketId(17, 134 | (1 << 16)));
+
+ for (uint32_t i=0; i<local.size(); ++i) {
+ calc.getIdealStorageNodes(local[i]);
+ }
+
+ CPPUNIT_ASSERT_EQUAL(4u, cache.getMissCount());
+ CPPUNIT_ASSERT_EQUAL(0u, cache.getHitCount());
+
+ for (uint32_t i=0; i<local.size(); ++i) {
+ calc.getIdealStorageNodes(local[i]);
+ }
+
+ CPPUNIT_ASSERT_EQUAL(4u, cache.getMissCount());
+ CPPUNIT_ASSERT_EQUAL(4u, cache.getHitCount());
+}
+
+void
+IdealNodeCalculatorCacheTest::testBucketsSameCacheSlot()
+{
+ ClusterState state("bits:6 storage:10");
+ Distribution distr(Distribution::getDefaultDistributionConfig(3, 10));
+ IdealNodeCalculatorImpl::SP impl(new IdealNodeCalculatorImpl);
+ IdealNodeCalculatorCache cache(impl, 1); // Only one slot available
+
+ IdealNodeCalculatorConfigurable& configurable(cache);
+ IdealNodeCalculator& calc(cache);
+ configurable.setDistribution(distr);
+ configurable.setClusterState(state);
+
+ // See that you don't get same result as last one
+ std::string expected("[storage.8, storage.9, storage.6]");
+ CPPUNIT_ASSERT_EQUAL(
+ expected,
+ calc.getIdealStorageNodes(document::BucketId(16, 5)).toString());
+ expected = "[storage.8, storage.6, storage.1]";
+ CPPUNIT_ASSERT_EQUAL(
+ expected,
+ calc.getIdealStorageNodes(document::BucketId(16, 6)).toString());
+}
+
+void
+IdealNodeCalculatorCacheTest::testCacheInvalidationOnChanges()
+{
+ ClusterState state("bits:6 storage:10");
+ Distribution distr(Distribution::getDefaultDistributionConfig(3, 10));
+ IdealNodeCalculatorImpl::SP impl(new IdealNodeCalculatorImpl);
+ IdealNodeCalculatorCache cache(impl, 1); // Only one slot available
+
+ IdealNodeCalculatorConfigurable& configurable(cache);
+ IdealNodeCalculator& calc(cache);
+ configurable.setDistribution(distr);
+ configurable.setClusterState(state);
+
+ // See that you don't get same result as last one
+ std::string expected("[storage.8, storage.9, storage.6]");
+ CPPUNIT_ASSERT_EQUAL(
+ expected,
+ calc.getIdealStorageNodes(document::BucketId(16, 5)).toString());
+
+ CPPUNIT_ASSERT_EQUAL(1u, cache.getMissCount());
+ CPPUNIT_ASSERT_EQUAL(0u, cache.getHitCount());
+
+ configurable.setClusterState(state);
+
+ CPPUNIT_ASSERT_EQUAL(
+ expected,
+ calc.getIdealStorageNodes(document::BucketId(16, 5)).toString());
+
+ CPPUNIT_ASSERT_EQUAL(2u, cache.getMissCount());
+ CPPUNIT_ASSERT_EQUAL(0u, cache.getHitCount());
+
+ configurable.setDistribution(distr);
+
+ CPPUNIT_ASSERT_EQUAL(
+ expected,
+ calc.getIdealStorageNodes(document::BucketId(16, 5)).toString());
+
+ CPPUNIT_ASSERT_EQUAL(3u, cache.getMissCount());
+ CPPUNIT_ASSERT_EQUAL(0u, cache.getHitCount());
+}
+
+void
+IdealNodeCalculatorCacheTest::testDifferentUpStates()
+{
+ ClusterState state("bits:6 storage:10 .6.s:m .8.s:r");
+ Distribution distr(Distribution::getDefaultDistributionConfig(3, 10));
+ IdealNodeCalculatorImpl::SP impl(new IdealNodeCalculatorImpl);
+ IdealNodeCalculatorCache cache(impl, 4);
+
+ IdealNodeCalculatorConfigurable& configurable(cache);
+ IdealNodeCalculator& calc(cache);
+ configurable.setDistribution(distr);
+ configurable.setClusterState(state);
+
+ std::string expected("[storage.9, storage.4, storage.1]");
+ CPPUNIT_ASSERT_EQUAL(
+ expected,
+ calc.getIdealStorageNodes(document::BucketId(16, 5),
+ IdealNodeCalculator::UpInit).toString());
+
+ expected = "[storage.9, storage.6, storage.4]";
+ CPPUNIT_ASSERT_EQUAL(
+ expected,
+ calc.getIdealStorageNodes(
+ document::BucketId(16, 5),
+ IdealNodeCalculator::UpInitMaintenance).toString());
+}
+
+void
+IdealNodeCalculatorCacheTest::testDifferentNodeTypes()
+{
+ ClusterState state("bits:6 distributor:10 storage:10 .6.s:m .8.s:r");
+ Distribution distr(Distribution::getDefaultDistributionConfig(3, 10));
+ IdealNodeCalculatorImpl::SP impl(new IdealNodeCalculatorImpl);
+ IdealNodeCalculatorCache cache(impl, 4);
+
+ IdealNodeCalculatorConfigurable& configurable(cache);
+ IdealNodeCalculator& calc(cache);
+ configurable.setDistribution(distr);
+ configurable.setClusterState(state);
+
+ std::string expected("[storage.9, storage.4, storage.1]");
+ CPPUNIT_ASSERT_EQUAL(
+ expected,
+ calc.getIdealStorageNodes(document::BucketId(16, 5)).toString());
+
+ expected = "[distributor.8]";
+ CPPUNIT_ASSERT_EQUAL(
+ expected,
+ calc.getIdealDistributorNodes(
+ document::BucketId(16, 5)).toString());
+}
+
+namespace {
+
+ uint64_t getCurrentTimeInMicros() {
+ struct timeval mytime;
+ gettimeofday(&mytime, 0);
+ return mytime.tv_sec * 1000000llu + mytime.tv_usec;
+ }
+
+ void addBucketTree(std::vector<document::BucketId>& v,
+ uint64_t location,
+ uint32_t currentUsedBits,
+ uint32_t maxUsedBits)
+ {
+ document::BucketId id(currentUsedBits, location);
+ v.push_back(id);
+ if (currentUsedBits < maxUsedBits) {
+ addBucketTree(v, location,
+ currentUsedBits + 1, maxUsedBits);
+ addBucketTree(v, location | (uint64_t(1) << currentUsedBits),
+ currentUsedBits + 1, maxUsedBits);
+ }
+ }
+
+ uint64_t runPerformanceTest(IdealNodeCalculator& calc) {
+ std::vector<document::BucketId> buckets;
+
+ // Addvarious location split levels for a user
+ addBucketTree(buckets, 123, 20, 22);
+ // Add various gid bit split levels for a user
+ addBucketTree(buckets, 123, 40, 42);
+
+ {
+ std::set<document::BucketId> uniqueBuckets;
+ for (uint32_t i=0; i<buckets.size(); ++i) {
+ uniqueBuckets.insert(buckets[i]);
+ calc.getIdealStorageNodes(buckets[i]);
+ }
+ CPPUNIT_ASSERT_EQUAL(buckets.size(), uniqueBuckets.size());
+ CPPUNIT_ASSERT_EQUAL(size_t(14), buckets.size());
+ }
+ IdealNodeCalculatorCache* cache(dynamic_cast<IdealNodeCalculatorCache*>(
+ &calc));
+ if (cache != 0) cache->clearCounts();
+ uint32_t value;
+ uint64_t start = getCurrentTimeInMicros();
+ for (uint32_t j=0; j<1024; ++j) {
+ for (uint32_t i=0; i<buckets.size(); ++i) {
+ IdealNodeList result(calc.getIdealStorageNodes(buckets[i]));
+ value += (result[0].getIndex() + result[1].getIndex())
+ / result[2].getIndex();
+ }
+ }
+ uint64_t stop = getCurrentTimeInMicros();
+ return (stop - start);
+ }
+
+ struct MapIdealNodeCalculator : public IdealNodeCalculator {
+ mutable std::map<document::BucketId, IdealNodeList> values;
+ const IdealNodeCalculator& calc;
+
+ MapIdealNodeCalculator(const IdealNodeCalculator& c) : calc(c) {}
+
+ virtual IdealNodeList getIdealNodes(const NodeType& nodeType,
+ const document::BucketId& bucketId,
+ UpStates upStates) const
+ {
+ std::map<document::BucketId, IdealNodeList>::const_iterator it(
+ values.find(bucketId));
+ if (it != values.end()) return it->second;
+ IdealNodeList result(
+ calc.getIdealNodes(nodeType, bucketId, upStates));
+ values[bucketId] = result;
+ return result;
+ }
+ };
+}
+
+void
+IdealNodeCalculatorCacheTest::testPerformance()
+{
+ ClusterState state("bits:18 distributor:100 storage:100 .6.s:m .8.s:r");
+ Distribution distr(Distribution::getDefaultDistributionConfig(3, 100));
+ IdealNodeCalculatorImpl::SP impl(new IdealNodeCalculatorImpl);
+ impl->setDistribution(distr);
+ impl->setClusterState(state);
+
+ uint64_t rawPerformance = runPerformanceTest(*impl);
+
+ IdealNodeCalculatorCache cache(impl, 14);
+
+ uint64_t cachePerformance = runPerformanceTest(cache);
+ double hitrate = (100.0 * cache.getHitCount()
+ / (cache.getHitCount() + cache.getMissCount()));
+ CPPUNIT_ASSERT(hitrate > 99.99);
+
+ MapIdealNodeCalculator mapCalc(*impl);
+
+ uint64_t mapPerformance = runPerformanceTest(mapCalc);
+
+ IdealNodeCalculatorCache cache2(impl, 13);
+ uint64_t cacheMissPerformance = runPerformanceTest(cache2);
+ double hitrate2 = (100.0 * cache2.getHitCount()
+ / (cache2.getHitCount() + cache2.getMissCount()));
+ CPPUNIT_ASSERT(hitrate2 < 0.01);
+
+ std::cerr << "\n"
+ << " Cache is "
+ << (static_cast<double>(rawPerformance) / cachePerformance)
+ << " x faster than skipping cache with 100% hitrate\n"
+ << " Cache is "
+ << (static_cast<double>(mapPerformance) / cachePerformance)
+ << " x faster than std::map cache with all data\n"
+ << " Cache is "
+ << (static_cast<double>(rawPerformance) / cacheMissPerformance)
+ << " x faster than skipping cache with 0% hitrate\n";
+}
+
+} // lib
+} // storage
diff --git a/vdslib/src/tests/distribution/idealnodecalculatorimpltest.cpp b/vdslib/src/tests/distribution/idealnodecalculatorimpltest.cpp
new file mode 100644
index 00000000000..dcecf935e1f
--- /dev/null
+++ b/vdslib/src/tests/distribution/idealnodecalculatorimpltest.cpp
@@ -0,0 +1,46 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/vdslib/distribution/idealnodecalculatorimpl.h>
+#include <vespa/vdstestlib/cppunit/macros.h>
+
+namespace storage {
+namespace lib {
+
+struct IdealNodeCalculatorImplTest : public CppUnit::TestFixture {
+
+ void testNormalUsage();
+
+ CPPUNIT_TEST_SUITE(IdealNodeCalculatorImplTest);
+ CPPUNIT_TEST(testNormalUsage);
+ CPPUNIT_TEST_SUITE_END();
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(IdealNodeCalculatorImplTest);
+
+/**
+ * Class is just a wrapper for distribution, so little needs to be tested. Just
+ * that:
+ *
+ * - get ideal nodes calls gets propagated correctly.
+ * - Changes in distribution/cluster state is picked up.
+ */
+
+void
+IdealNodeCalculatorImplTest::testNormalUsage()
+{
+ ClusterState state("storage:10");
+ Distribution distr(Distribution::getDefaultDistributionConfig(3, 10));
+ IdealNodeCalculatorImpl impl;
+ IdealNodeCalculatorConfigurable& configurable(impl);
+ IdealNodeCalculator& calc(impl);
+ configurable.setDistribution(distr);
+ configurable.setClusterState(state);
+
+ std::string expected("[storage.8, storage.9, storage.6]");
+ CPPUNIT_ASSERT_EQUAL(
+ expected,
+ calc.getIdealStorageNodes(document::BucketId(16, 5)).toString());
+}
+
+} // lib
+} // storage
diff --git a/vdslib/src/tests/distribution/randombucket.cpp b/vdslib/src/tests/distribution/randombucket.cpp
new file mode 100644
index 00000000000..57b6798068e
--- /dev/null
+++ b/vdslib/src/tests/distribution/randombucket.cpp
@@ -0,0 +1,51 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#include <vespa/fastos/fastos.h>
+#include <vespa/vdslib/state/random.h>
+#include <tests/distribution/randombucket.h>
+#include <iostream>
+
+namespace RandomBucket{
+
+uint64_t _num_users;
+uint64_t _locationbits;
+bool _scheme = false;
+storage::lib::RandomGen rg;
+
+void setUserDocScheme(uint64_t num_users, uint64_t locationbits)
+{
+ _scheme = true;
+ _num_users = num_users;
+ _locationbits = locationbits;
+}
+
+void setDocScheme()
+{
+ _scheme = false;
+}
+
+uint64_t get()
+{
+ uint64_t u = rg.nextUint64();
+ if(_scheme){ // userdoc
+ uint64_t shift = 8 * sizeof(uint64_t) - _locationbits;
+ uint64_t lsb = u << shift;
+ lsb >>= shift;
+ lsb %= _num_users;
+ u >>= _locationbits;
+ u <<= _locationbits;
+ u |= lsb;
+ }
+ return u;
+}
+
+void setSeed(int seed)
+{
+ if(seed == -1){
+ rg = storage::lib::RandomGen();
+ }
+ else{
+ rg.setSeed(seed);
+ }
+}
+
+}
diff --git a/vdslib/src/tests/distribution/randombucket.h b/vdslib/src/tests/distribution/randombucket.h
new file mode 100644
index 00000000000..fcede950c52
--- /dev/null
+++ b/vdslib/src/tests/distribution/randombucket.h
@@ -0,0 +1,11 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#pragma once
+
+namespace RandomBucket{
+
+ void setUserDocScheme(uint64_t num_users, uint64_t locationbits);
+ void setDocScheme();
+ uint64_t get();
+ void setSeed(int seed=-1);
+}
+
diff --git a/vdslib/src/tests/distribution/testdata/.gitignore b/vdslib/src/tests/distribution/testdata/.gitignore
new file mode 100644
index 00000000000..97209fbdc9c
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/.gitignore
@@ -0,0 +1 @@
+cpp_*.distribution
diff --git a/vdslib/src/tests/distribution/testdata/41-distributordistribution b/vdslib/src/tests/distribution/testdata/41-distributordistribution
new file mode 100644
index 00000000000..b07f39ba941
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/41-distributordistribution
@@ -0,0 +1,65536 @@
+6
+3
+4
+8
+8
+8
+8
+8
+8
+3
+8
+8
+2
+5
+0
+1
+7
+7
+5
+1
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+4
+5
+0
+9
+7
+3
+9
+8
+2
+2
+4
+9
+5
+2
+6
+8
+7
+7
+3
+9
+7
+5
+2
+1
+8
+6
+1
+6
+6
+0
+7
+2
+8
+8
+5
+1
+9
+6
+1
+4
+6
+2
+7
+5
+9
+1
+5
+3
+7
+6
+2
+5
+3
+3
+4
+4
+5
+5
+0
+9
+9
+7
+9
+5
+7
+4
+1
+5
+9
+2
+3
+3
+2
+9
+4
+4
+5
+5
+3
+3
+1
+0
+0
+4
+9
+5
+9
+3
+1
+7
+6
+2
+0
+6
+4
+1
+6
+6
+5
+4
+3
+1
+4
+2
+9
+5
+7
+5
+4
+7
+4
+4
+9
+2
+0
+7
+1
+1
+5
+9
+5
+4
+2
+1
+3
+6
+7
+3
+6
+0
+9
+2
+0
+0
+3
+3
+9
+6
+7
+0
+6
+0
+3
+6
+9
+4
+6
+0
+3
+0
+3
+6
+4
+7
+2
+6
+1
+1
+3
+0
+5
+3
+4
+1
+6
+4
+1
+6
+0
+5
+0
+7
+4
+1
+5
+4
+3
+3
+0
+5
+4
+9
+5
+4
+9
+7
+9
+7
+7
+9
+6
+5
+4
+5
+0
+2
+1
+7
+9
+7
+7
+1
+4
+3
+2
+2
+9
+6
+6
+3
+1
+0
+0
+6
+7
+5
+1
+1
+5
+6
+6
+9
+9
+1
+5
+9
+5
+9
+9
+8
+8
+8
+8
+8
+8
+8
+8
+6
+8
+8
+8
+3
+4
+4
+2
+4
+6
+1
+5
+7
+7
+6
+6
+5
+2
+0
+0
+9
+8
+3
+4
+0
+7
+6
+6
+4
+9
+3
+1
+8
+8
+0
+2
+9
+8
+8
+5
+2
+8
+8
+8
+9
+8
+3
+8
+4
+2
+8
+5
+7
+9
+1
+7
+3
+1
+7
+1
+5
+9
+5
+0
+1
+0
+4
+2
+0
+9
+5
+8
+2
+5
+7
+7
+6
+9
+0
+8
+5
+6
+6
+6
+7
+1
+7
+4
+3
+0
+5
+2
+1
+9
+6
+3
+7
+7
+9
+2
+7
+7
+6
+5
+2
+2
+6
+1
+1
+4
+4
+8
+4
+7
+9
+5
+4
+2
+0
+0
+1
+0
+7
+5
+6
+4
+6
+6
+3
+9
+2
+1
+5
+6
+4
+1
+3
+9
+6
+2
+2
+0
+1
+4
+3
+9
+4
+1
+7
+2
+6
+3
+3
+9
+5
+6
+0
+5
+9
+1
+7
+9
+3
+4
+7
+7
+7
+3
+3
+9
+7
+4
+2
+1
+5
+3
+6
+6
+0
+5
+0
+5
+7
+0
+4
+1
+3
+5
+5
+6
+2
+3
+1
+7
+6
+6
+2
+4
+9
+7
+0
+5
+3
+6
+2
+0
+9
+4
+5
+4
+0
+7
+3
+1
+9
+6
+6
+4
+5
+0
+1
+5
+2
+9
+5
+1
+7
+4
+4
+0
+9
+9
+2
+3
+3
+1
+2
+4
+5
+9
+4
+2
+1
+7
+6
+9
+8
+0
+7
+3
+3
+7
+9
+9
+4
+8
+4
+3
+2
+5
+9
+5
+2
+1
+7
+7
+3
+2
+5
+9
+1
+8
+2
+1
+3
+8
+3
+7
+5
+7
+8
+5
+0
+0
+3
+0
+2
+1
+6
+6
+9
+4
+5
+9
+8
+4
+8
+4
+5
+7
+6
+9
+6
+0
+2
+0
+6
+6
+4
+2
+1
+7
+5
+1
+6
+3
+3
+4
+4
+6
+4
+7
+2
+5
+7
+5
+6
+7
+0
+1
+9
+2
+5
+9
+5
+1
+1
+4
+9
+3
+3
+2
+0
+1
+1
+4
+9
+9
+1
+0
+3
+7
+2
+1
+2
+7
+5
+1
+5
+2
+2
+5
+0
+9
+6
+6
+3
+5
+7
+2
+1
+9
+7
+2
+9
+5
+1
+2
+1
+3
+3
+2
+3
+1
+7
+7
+2
+1
+4
+7
+2
+1
+1
+9
+2
+4
+0
+1
+4
+2
+6
+1
+6
+6
+2
+3
+4
+9
+4
+5
+4
+5
+6
+3
+9
+9
+5
+0
+4
+7
+6
+6
+7
+0
+6
+0
+5
+6
+4
+5
+3
+2
+7
+7
+7
+0
+6
+3
+1
+5
+3
+1
+6
+1
+7
+7
+4
+9
+1
+9
+0
+5
+6
+3
+2
+9
+4
+1
+0
+0
+5
+7
+9
+1
+3
+6
+7
+5
+8
+4
+4
+8
+8
+5
+0
+8
+0
+6
+7
+8
+8
+8
+6
+6
+9
+1
+2
+4
+8
+8
+8
+8
+7
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+4
+2
+4
+0
+9
+4
+7
+5
+3
+6
+2
+7
+4
+8
+8
+8
+8
+3
+6
+8
+9
+8
+8
+2
+8
+0
+1
+8
+9
+5
+6
+5
+0
+2
+0
+3
+6
+8
+2
+7
+7
+9
+4
+3
+0
+8
+8
+6
+3
+8
+8
+1
+9
+7
+7
+7
+3
+9
+8
+3
+2
+2
+7
+1
+4
+7
+9
+0
+7
+0
+2
+5
+0
+1
+9
+1
+5
+4
+0
+1
+3
+9
+3
+2
+5
+6
+4
+7
+1
+4
+0
+6
+2
+0
+1
+5
+1
+6
+6
+7
+5
+1
+2
+0
+4
+5
+4
+4
+3
+3
+6
+6
+6
+0
+9
+2
+1
+3
+5
+1
+2
+9
+9
+1
+4
+3
+7
+9
+2
+1
+7
+4
+7
+3
+6
+7
+6
+0
+5
+6
+1
+9
+2
+0
+6
+0
+3
+6
+5
+9
+0
+1
+7
+4
+1
+2
+1
+4
+9
+6
+2
+2
+5
+7
+7
+2
+9
+9
+5
+5
+2
+5
+3
+3
+9
+4
+9
+7
+3
+0
+7
+3
+9
+2
+4
+6
+4
+4
+3
+7
+0
+1
+2
+2
+1
+9
+1
+6
+6
+5
+0
+1
+0
+9
+4
+7
+7
+1
+0
+6
+0
+7
+5
+5
+9
+3
+6
+1
+7
+5
+0
+5
+1
+7
+2
+8
+8
+8
+8
+8
+8
+8
+8
+3
+7
+8
+9
+5
+3
+4
+7
+4
+4
+9
+1
+0
+3
+2
+5
+7
+7
+1
+2
+6
+6
+3
+6
+9
+7
+5
+2
+2
+5
+7
+7
+2
+2
+9
+1
+3
+2
+0
+0
+9
+0
+4
+3
+4
+5
+3
+7
+9
+1
+2
+5
+4
+3
+0
+2
+7
+9
+7
+2
+5
+4
+4
+1
+4
+9
+0
+6
+1
+3
+5
+8
+7
+9
+0
+7
+0
+3
+6
+6
+5
+9
+2
+9
+7
+7
+1
+2
+6
+1
+5
+6
+2
+3
+9
+3
+1
+0
+1
+4
+1
+2
+6
+5
+3
+9
+7
+7
+1
+3
+2
+1
+3
+9
+2
+5
+4
+1
+9
+7
+2
+0
+3
+4
+2
+2
+9
+3
+7
+7
+3
+0
+7
+2
+9
+3
+4
+5
+0
+1
+6
+0
+9
+4
+6
+4
+1
+6
+7
+4
+2
+0
+4
+5
+7
+2
+9
+5
+3
+4
+2
+4
+4
+1
+2
+9
+3
+1
+3
+2
+7
+0
+4
+2
+5
+3
+6
+5
+6
+6
+7
+5
+2
+7
+2
+1
+9
+5
+0
+6
+6
+2
+2
+3
+9
+6
+5
+7
+5
+3
+6
+2
+9
+6
+9
+1
+0
+3
+5
+7
+9
+0
+3
+4
+1
+8
+8
+1
+8
+9
+3
+5
+8
+8
+7
+8
+8
+9
+1
+2
+0
+5
+8
+8
+8
+8
+8
+8
+8
+1
+6
+7
+0
+9
+4
+1
+8
+8
+8
+8
+8
+3
+1
+6
+4
+7
+9
+5
+6
+3
+3
+0
+8
+8
+6
+2
+6
+1
+3
+7
+8
+0
+5
+0
+1
+3
+3
+4
+7
+8
+5
+3
+2
+0
+3
+0
+9
+9
+7
+7
+6
+3
+3
+0
+9
+7
+6
+6
+8
+8
+3
+2
+1
+0
+7
+2
+8
+5
+0
+6
+2
+4
+6
+6
+4
+5
+7
+7
+3
+9
+0
+5
+5
+2
+5
+6
+9
+0
+2
+5
+1
+3
+3
+4
+4
+5
+4
+9
+7
+7
+9
+3
+1
+9
+0
+1
+2
+1
+9
+3
+7
+7
+1
+6
+0
+3
+2
+0
+3
+9
+5
+1
+0
+3
+9
+7
+5
+1
+1
+5
+6
+4
+9
+9
+2
+1
+6
+7
+7
+6
+1
+9
+6
+2
+3
+0
+6
+1
+5
+3
+6
+6
+7
+7
+6
+4
+9
+2
+4
+9
+3
+4
+1
+0
+4
+2
+3
+0
+9
+6
+5
+9
+7
+3
+6
+0
+3
+0
+6
+5
+6
+3
+4
+6
+4
+0
+6
+9
+2
+3
+1
+4
+6
+4
+7
+0
+1
+3
+5
+4
+9
+7
+4
+5
+4
+3
+7
+3
+9
+9
+5
+4
+5
+3
+5
+2
+9
+7
+1
+0
+2
+0
+7
+7
+6
+6
+5
+6
+7
+7
+1
+3
+8
+8
+8
+8
+8
+8
+8
+8
+1
+8
+8
+8
+0
+6
+4
+2
+4
+9
+6
+6
+6
+2
+0
+4
+0
+9
+1
+5
+7
+1
+9
+6
+8
+4
+4
+5
+4
+8
+9
+8
+8
+3
+5
+4
+8
+8
+0
+8
+0
+8
+7
+1
+8
+8
+8
+5
+4
+3
+1
+8
+5
+2
+6
+6
+1
+5
+0
+4
+9
+4
+4
+9
+4
+0
+2
+1
+0
+4
+9
+3
+4
+0
+5
+2
+2
+5
+0
+3
+0
+1
+7
+0
+9
+2
+0
+5
+5
+3
+3
+7
+9
+1
+5
+7
+6
+3
+2
+6
+9
+5
+9
+4
+2
+6
+3
+2
+7
+0
+6
+7
+4
+3
+3
+6
+4
+2
+1
+9
+7
+1
+6
+4
+3
+9
+2
+6
+1
+3
+1
+2
+1
+9
+4
+2
+4
+7
+5
+7
+3
+9
+0
+0
+0
+4
+4
+0
+0
+7
+7
+5
+5
+4
+9
+3
+1
+9
+5
+2
+0
+6
+9
+4
+3
+9
+0
+2
+0
+3
+7
+7
+2
+6
+4
+6
+4
+2
+1
+3
+0
+2
+5
+0
+7
+7
+7
+3
+3
+4
+0
+5
+0
+9
+2
+3
+3
+4
+2
+1
+5
+7
+5
+2
+3
+6
+7
+2
+9
+9
+0
+6
+8
+4
+4
+8
+4
+6
+7
+8
+8
+1
+6
+8
+8
+5
+8
+8
+6
+6
+2
+6
+8
+8
+8
+8
+8
+8
+3
+2
+8
+8
+5
+8
+7
+0
+1
+7
+8
+2
+8
+4
+8
+4
+9
+0
+3
+7
+2
+8
+1
+3
+2
+0
+8
+0
+8
+2
+8
+3
+9
+1
+6
+6
+8
+0
+8
+1
+0
+9
+0
+4
+4
+0
+6
+6
+5
+3
+7
+5
+0
+7
+8
+3
+7
+4
+3
+4
+6
+5
+4
+3
+9
+9
+2
+7
+1
+7
+7
+9
+0
+4
+2
+2
+4
+0
+9
+2
+3
+5
+3
+6
+6
+6
+4
+7
+3
+1
+6
+6
+7
+4
+0
+4
+1
+2
+3
+1
+9
+5
+6
+5
+7
+3
+4
+2
+6
+9
+7
+2
+5
+3
+7
+7
+4
+9
+0
+9
+5
+7
+3
+0
+2
+5
+4
+1
+0
+3
+7
+7
+5
+2
+2
+2
+1
+0
+0
+1
+3
+9
+7
+2
+4
+5
+6
+3
+7
+0
+1
+9
+2
+3
+5
+1
+2
+4
+6
+4
+6
+1
+1
+4
+3
+7
+2
+1
+4
+5
+9
+2
+0
+6
+3
+6
+5
+4
+9
+4
+4
+9
+0
+0
+6
+6
+9
+3
+3
+1
+7
+7
+0
+2
+9
+3
+5
+4
+5
+0
+9
+2
+6
+6
+5
+5
+2
+7
+6
+9
+5
+2
+7
+7
+6
+6
+6
+9
+5
+9
+3
+4
+7
+4
+1
+9
+7
+3
+3
+5
+9
+5
+6
+2
+8
+8
+8
+8
+5
+8
+0
+8
+8
+8
+8
+3
+1
+4
+5
+9
+4
+5
+1
+5
+3
+7
+2
+4
+6
+6
+7
+6
+9
+8
+1
+4
+2
+1
+4
+0
+4
+9
+3
+6
+1
+2
+6
+4
+1
+6
+8
+8
+8
+8
+8
+3
+9
+8
+2
+1
+8
+0
+8
+5
+6
+3
+6
+6
+2
+2
+7
+7
+1
+3
+0
+4
+0
+5
+4
+5
+9
+9
+4
+0
+7
+0
+2
+1
+9
+9
+3
+2
+8
+6
+1
+0
+9
+4
+4
+9
+1
+7
+1
+6
+9
+1
+7
+3
+3
+4
+4
+5
+2
+5
+0
+1
+0
+7
+4
+0
+9
+2
+1
+7
+3
+1
+0
+4
+1
+7
+5
+3
+3
+5
+3
+7
+9
+9
+4
+2
+2
+7
+3
+7
+2
+0
+5
+3
+7
+2
+5
+7
+9
+2
+0
+3
+6
+0
+6
+6
+7
+4
+4
+7
+4
+6
+3
+1
+6
+9
+6
+2
+0
+3
+1
+5
+2
+9
+1
+0
+0
+0
+7
+6
+5
+9
+5
+3
+1
+3
+3
+4
+3
+1
+7
+1
+0
+3
+9
+2
+1
+4
+4
+7
+7
+1
+0
+7
+5
+9
+7
+7
+4
+2
+9
+5
+3
+9
+2
+5
+6
+7
+1
+7
+7
+7
+0
+5
+8
+8
+2
+8
+3
+8
+8
+8
+8
+8
+8
+8
+7
+7
+4
+1
+2
+9
+0
+9
+0
+2
+1
+0
+9
+6
+3
+1
+1
+0
+9
+7
+8
+5
+4
+3
+8
+8
+9
+0
+5
+7
+6
+2
+7
+8
+8
+8
+2
+8
+5
+6
+8
+5
+8
+8
+4
+2
+8
+8
+6
+6
+3
+0
+5
+9
+2
+1
+7
+7
+3
+4
+2
+4
+7
+7
+2
+5
+9
+8
+2
+1
+8
+0
+5
+0
+9
+8
+7
+5
+7
+7
+4
+1
+5
+9
+1
+5
+2
+5
+1
+3
+1
+9
+6
+6
+5
+1
+4
+1
+3
+9
+8
+2
+5
+4
+6
+4
+6
+9
+0
+1
+1
+6
+4
+2
+3
+5
+1
+1
+0
+4
+0
+3
+5
+0
+7
+0
+9
+1
+0
+4
+3
+1
+4
+0
+9
+5
+6
+6
+1
+4
+0
+7
+9
+7
+5
+2
+5
+0
+6
+6
+4
+9
+7
+7
+2
+1
+5
+6
+9
+9
+6
+3
+0
+6
+2
+6
+1
+0
+2
+5
+4
+5
+3
+2
+7
+9
+6
+1
+6
+3
+9
+7
+2
+0
+0
+0
+5
+3
+9
+4
+1
+5
+0
+4
+4
+2
+4
+1
+9
+5
+7
+2
+7
+3
+6
+0
+9
+6
+0
+1
+5
+4
+7
+4
+4
+7
+1
+6
+2
+6
+5
+3
+3
+4
+4
+6
+0
+2
+9
+7
+3
+6
+1
+5
+4
+3
+9
+2
+1
+9
+0
+2
+9
+9
+1
+2
+3
+4
+2
+6
+0
+7
+0
+5
+3
+1
+1
+5
+2
+1
+6
+6
+6
+6
+7
+7
+1
+9
+2
+1
+5
+1
+5
+8
+0
+6
+8
+2
+8
+8
+9
+8
+8
+5
+8
+3
+2
+8
+9
+0
+2
+4
+8
+8
+0
+8
+4
+8
+8
+8
+8
+3
+8
+8
+3
+9
+8
+5
+8
+3
+7
+4
+3
+4
+4
+0
+4
+5
+2
+6
+9
+8
+1
+8
+8
+6
+7
+7
+3
+8
+6
+6
+2
+4
+5
+0
+5
+1
+7
+7
+6
+5
+6
+6
+1
+9
+1
+6
+5
+7
+9
+3
+7
+7
+6
+7
+2
+8
+5
+0
+2
+0
+1
+5
+4
+7
+8
+3
+2
+0
+5
+0
+1
+2
+6
+6
+7
+5
+0
+7
+0
+3
+2
+1
+4
+6
+2
+1
+5
+0
+9
+9
+3
+7
+1
+2
+2
+1
+9
+0
+1
+4
+4
+5
+4
+7
+7
+3
+5
+0
+7
+1
+9
+5
+0
+3
+3
+0
+2
+4
+9
+5
+1
+3
+6
+6
+7
+7
+5
+6
+6
+3
+4
+0
+3
+7
+9
+9
+5
+7
+6
+3
+6
+6
+4
+9
+1
+3
+0
+6
+6
+5
+7
+1
+6
+7
+2
+5
+0
+2
+0
+9
+4
+5
+8
+1
+8
+8
+3
+2
+8
+8
+1
+8
+8
+8
+3
+8
+8
+0
+7
+3
+2
+4
+8
+8
+7
+8
+4
+8
+8
+8
+8
+8
+1
+4
+9
+3
+6
+4
+7
+4
+4
+7
+9
+5
+8
+8
+8
+8
+8
+0
+9
+8
+8
+1
+8
+7
+8
+8
+9
+3
+1
+8
+4
+5
+8
+2
+1
+7
+4
+7
+2
+2
+0
+5
+0
+6
+5
+1
+3
+4
+6
+6
+5
+9
+5
+8
+3
+5
+7
+7
+9
+9
+0
+2
+5
+8
+5
+2
+0
+6
+7
+6
+6
+0
+9
+1
+1
+5
+0
+3
+7
+7
+3
+0
+7
+9
+0
+3
+0
+1
+2
+4
+9
+4
+5
+3
+1
+7
+9
+2
+2
+1
+4
+1
+4
+3
+9
+0
+1
+2
+1
+4
+6
+4
+4
+7
+0
+1
+5
+3
+3
+5
+2
+1
+6
+6
+6
+6
+7
+3
+1
+7
+2
+0
+7
+7
+5
+9
+3
+0
+2
+0
+9
+3
+7
+6
+3
+1
+7
+7
+7
+1
+1
+9
+3
+4
+6
+6
+1
+6
+4
+1
+3
+1
+1
+5
+9
+2
+6
+6
+3
+5
+2
+7
+9
+1
+7
+2
+5
+7
+5
+4
+9
+0
+4
+0
+1
+6
+4
+1
+9
+5
+7
+7
+4
+0
+3
+1
+0
+2
+0
+4
+4
+3
+4
+7
+9
+9
+5
+2
+0
+4
+3
+0
+1
+5
+5
+1
+0
+4
+3
+7
+2
+9
+6
+5
+6
+6
+9
+1
+3
+9
+8
+8
+7
+8
+1
+8
+6
+8
+8
+2
+8
+8
+6
+6
+4
+9
+6
+5
+6
+1
+7
+6
+0
+7
+5
+1
+1
+2
+8
+8
+8
+8
+5
+8
+8
+9
+6
+6
+8
+8
+2
+0
+7
+5
+3
+5
+0
+1
+8
+8
+6
+8
+4
+8
+8
+8
+8
+1
+8
+8
+1
+6
+5
+0
+0
+0
+6
+2
+2
+3
+4
+7
+2
+2
+5
+9
+5
+2
+3
+8
+8
+8
+1
+0
+7
+7
+3
+5
+5
+4
+2
+9
+8
+3
+3
+2
+5
+7
+0
+2
+0
+5
+3
+0
+3
+6
+1
+6
+0
+5
+1
+4
+9
+6
+8
+9
+6
+3
+7
+6
+9
+5
+2
+9
+0
+1
+7
+3
+6
+9
+7
+4
+1
+2
+1
+3
+9
+9
+5
+0
+5
+2
+0
+6
+0
+5
+7
+7
+1
+0
+2
+5
+5
+9
+1
+2
+5
+6
+4
+9
+3
+5
+0
+6
+0
+7
+9
+4
+3
+0
+7
+7
+2
+3
+9
+1
+1
+2
+5
+3
+4
+5
+1
+5
+7
+1
+7
+4
+1
+3
+2
+3
+3
+0
+5
+2
+7
+4
+5
+3
+2
+2
+0
+0
+1
+5
+9
+9
+3
+2
+1
+5
+6
+7
+9
+9
+3
+4
+6
+6
+9
+8
+2
+8
+6
+6
+3
+0
+9
+8
+7
+8
+1
+8
+8
+8
+9
+0
+6
+6
+8
+8
+8
+8
+8
+8
+8
+8
+8
+0
+3
+4
+0
+9
+8
+5
+5
+3
+7
+7
+1
+9
+5
+8
+2
+3
+8
+5
+9
+8
+8
+8
+7
+2
+8
+1
+5
+9
+8
+8
+6
+3
+6
+6
+5
+4
+6
+6
+9
+3
+2
+9
+8
+1
+0
+5
+0
+3
+4
+2
+2
+8
+0
+1
+5
+8
+3
+9
+7
+2
+1
+7
+9
+1
+0
+9
+3
+7
+2
+5
+7
+9
+2
+7
+6
+6
+5
+1
+9
+9
+6
+6
+4
+0
+8
+8
+9
+7
+6
+6
+3
+4
+4
+0
+4
+3
+5
+9
+5
+7
+4
+6
+4
+9
+2
+3
+3
+6
+0
+0
+1
+0
+4
+3
+2
+7
+1
+0
+9
+9
+7
+7
+3
+2
+2
+5
+1
+9
+0
+3
+4
+1
+9
+7
+0
+9
+5
+2
+1
+3
+5
+2
+6
+5
+0
+6
+4
+1
+3
+7
+9
+6
+0
+0
+0
+2
+9
+6
+7
+7
+1
+3
+5
+9
+3
+7
+1
+5
+7
+3
+9
+9
+3
+5
+5
+6
+0
+1
+9
+9
+4
+1
+4
+3
+7
+7
+2
+9
+1
+4
+6
+1
+4
+5
+7
+5
+7
+7
+6
+4
+9
+6
+4
+3
+2
+1
+7
+5
+9
+4
+0
+7
+5
+2
+2
+0
+1
+5
+5
+3
+0
+1
+0
+2
+5
+0
+5
+3
+6
+0
+8
+8
+9
+8
+8
+8
+2
+8
+1
+8
+8
+9
+2
+4
+4
+2
+3
+1
+9
+0
+0
+6
+3
+5
+3
+7
+6
+6
+8
+1
+8
+4
+8
+4
+4
+9
+1
+7
+6
+6
+8
+5
+3
+2
+6
+0
+8
+3
+2
+8
+8
+1
+8
+4
+8
+0
+4
+0
+1
+9
+4
+2
+7
+3
+1
+9
+5
+4
+6
+4
+4
+6
+4
+9
+2
+1
+8
+6
+9
+1
+3
+8
+6
+2
+2
+8
+9
+0
+2
+1
+4
+5
+0
+5
+6
+9
+6
+0
+3
+6
+5
+7
+0
+9
+0
+5
+7
+4
+1
+8
+5
+4
+0
+5
+1
+2
+2
+1
+9
+9
+4
+2
+3
+7
+4
+2
+9
+9
+7
+3
+3
+4
+3
+0
+4
+7
+6
+6
+2
+6
+0
+4
+1
+9
+6
+3
+0
+2
+7
+7
+6
+9
+1
+4
+4
+5
+6
+2
+9
+1
+7
+7
+6
+3
+1
+6
+2
+0
+0
+5
+3
+3
+9
+1
+5
+0
+7
+0
+3
+1
+9
+4
+7
+9
+4
+2
+1
+0
+4
+6
+7
+7
+1
+2
+9
+0
+5
+0
+4
+6
+4
+7
+5
+1
+7
+0
+2
+1
+1
+3
+9
+2
+2
+9
+1
+2
+2
+3
+9
+1
+8
+8
+4
+8
+8
+2
+8
+9
+8
+5
+8
+8
+0
+6
+7
+7
+3
+9
+2
+0
+8
+0
+8
+8
+8
+8
+8
+8
+7
+5
+8
+9
+4
+2
+0
+8
+0
+1
+8
+6
+7
+4
+3
+7
+1
+8
+5
+9
+5
+8
+6
+6
+8
+1
+0
+9
+0
+7
+8
+8
+2
+4
+4
+9
+5
+1
+3
+1
+9
+7
+5
+9
+1
+5
+7
+0
+9
+0
+2
+4
+0
+1
+3
+4
+9
+0
+4
+1
+2
+3
+5
+7
+2
+5
+1
+6
+2
+0
+5
+9
+1
+2
+1
+5
+7
+3
+3
+0
+0
+0
+5
+1
+4
+8
+3
+9
+1
+0
+2
+4
+7
+4
+3
+9
+4
+1
+7
+6
+9
+4
+4
+0
+3
+7
+5
+7
+6
+2
+7
+4
+3
+4
+4
+6
+1
+5
+3
+9
+6
+6
+2
+0
+9
+0
+5
+7
+2
+5
+6
+4
+2
+9
+6
+3
+7
+1
+0
+7
+0
+2
+4
+3
+1
+0
+5
+2
+4
+3
+1
+9
+3
+7
+7
+4
+9
+3
+0
+5
+0
+4
+1
+0
+2
+1
+4
+0
+5
+2
+3
+0
+1
+9
+1
+4
+6
+6
+3
+6
+9
+5
+0
+3
+6
+6
+7
+7
+4
+9
+6
+2
+2
+5
+0
+4
+2
+7
+5
+2
+1
+7
+4
+7
+4
+2
+4
+3
+6
+9
+3
+4
+5
+3
+0
+3
+0
+7
+5
+0
+6
+0
+6
+3
+9
+1
+6
+2
+1
+7
+1
+7
+8
+8
+8
+8
+8
+0
+8
+8
+8
+2
+8
+8
+6
+4
+4
+6
+9
+9
+3
+7
+5
+1
+2
+0
+9
+9
+3
+2
+7
+8
+9
+4
+2
+1
+4
+8
+4
+2
+9
+8
+1
+2
+5
+8
+8
+7
+8
+0
+8
+8
+8
+8
+8
+6
+8
+8
+4
+8
+6
+2
+2
+1
+0
+1
+2
+6
+5
+3
+1
+2
+6
+9
+7
+4
+4
+5
+6
+5
+7
+6
+8
+9
+0
+1
+5
+8
+9
+2
+7
+7
+1
+3
+7
+9
+0
+7
+1
+5
+1
+3
+6
+6
+8
+6
+5
+7
+9
+3
+3
+6
+8
+4
+6
+3
+4
+6
+0
+5
+1
+5
+4
+1
+2
+1
+4
+0
+3
+5
+5
+1
+9
+4
+2
+9
+4
+0
+7
+0
+9
+5
+3
+2
+7
+7
+4
+0
+9
+3
+5
+1
+2
+4
+7
+6
+2
+0
+2
+3
+5
+2
+0
+5
+9
+9
+2
+3
+3
+7
+1
+2
+7
+9
+5
+2
+3
+9
+6
+6
+5
+9
+0
+0
+3
+5
+1
+0
+2
+9
+6
+1
+3
+5
+9
+7
+0
+9
+2
+5
+7
+7
+9
+2
+4
+5
+0
+2
+4
+5
+3
+0
+9
+1
+5
+7
+0
+4
+3
+4
+1
+9
+0
+0
+4
+3
+8
+8
+3
+8
+8
+5
+8
+8
+8
+0
+7
+1
+6
+6
+0
+6
+2
+0
+9
+6
+4
+2
+1
+3
+3
+1
+3
+7
+1
+5
+8
+4
+0
+3
+2
+9
+5
+8
+7
+7
+8
+3
+0
+2
+8
+8
+8
+8
+2
+3
+1
+9
+7
+4
+4
+8
+5
+3
+8
+6
+3
+4
+4
+8
+9
+7
+0
+1
+0
+6
+8
+4
+9
+4
+4
+3
+3
+8
+1
+5
+6
+1
+6
+6
+3
+2
+7
+8
+9
+3
+1
+5
+6
+5
+6
+6
+9
+0
+2
+3
+5
+4
+3
+2
+9
+9
+0
+0
+4
+1
+5
+1
+9
+5
+7
+4
+1
+2
+1
+4
+9
+1
+5
+3
+6
+2
+9
+0
+1
+7
+5
+3
+9
+5
+2
+9
+5
+4
+0
+1
+3
+4
+4
+9
+4
+7
+1
+0
+2
+0
+1
+7
+8
+5
+4
+3
+1
+7
+3
+4
+5
+4
+7
+5
+4
+4
+2
+1
+6
+6
+1
+4
+5
+0
+5
+2
+7
+5
+1
+7
+2
+1
+6
+0
+5
+2
+6
+3
+7
+9
+7
+7
+6
+6
+6
+6
+9
+5
+2
+5
+0
+7
+1
+2
+9
+4
+4
+2
+4
+1
+7
+1
+9
+9
+5
+9
+1
+2
+0
+5
+9
+9
+7
+3
+3
+4
+9
+0
+4
+0
+2
+3
+7
+1
+9
+2
+4
+9
+7
+2
+3
+5
+0
+4
+1
+6
+4
+0
+5
+2
+6
+6
+7
+7
+6
+7
+5
+9
+1
+4
+0
+4
+4
+5
+4
+9
+2
+1
+7
+3
+2
+5
+3
+0
+7
+2
+2
+3
+5
+0
+3
+1
+6
+6
+1
+0
+8
+7
+8
+8
+8
+5
+6
+8
+8
+0
+8
+7
+3
+8
+7
+6
+7
+3
+8
+8
+4
+8
+8
+8
+8
+5
+2
+8
+8
+8
+4
+2
+9
+6
+0
+3
+3
+4
+7
+4
+4
+8
+8
+3
+2
+7
+8
+8
+9
+8
+4
+1
+3
+2
+0
+8
+9
+4
+7
+6
+3
+7
+3
+2
+9
+9
+1
+4
+0
+5
+7
+6
+1
+9
+6
+1
+2
+6
+5
+1
+9
+2
+6
+3
+3
+2
+2
+7
+0
+6
+0
+3
+3
+0
+2
+0
+8
+3
+1
+3
+9
+4
+7
+2
+4
+0
+7
+6
+9
+5
+4
+5
+7
+5
+1
+3
+2
+4
+6
+9
+0
+2
+7
+1
+9
+1
+2
+6
+5
+0
+4
+0
+6
+6
+7
+7
+6
+4
+1
+3
+5
+9
+3
+9
+2
+4
+2
+4
+1
+0
+3
+1
+7
+5
+2
+3
+7
+4
+4
+2
+6
+6
+5
+2
+0
+9
+0
+4
+3
+0
+4
+0
+1
+9
+3
+0
+1
+5
+4
+1
+9
+9
+7
+6
+5
+2
+1
+5
+6
+9
+0
+3
+4
+1
+7
+2
+7
+7
+5
+3
+0
+6
+0
+1
+5
+0
+5
+1
+6
+6
+9
+7
+4
+9
+4
+0
+3
+2
+9
+1
+0
+4
+5
+8
+9
+4
+6
+6
+0
+3
+0
+2
+3
+6
+7
+9
+8
+1
+8
+8
+6
+1
+8
+8
+8
+3
+8
+4
+1
+8
+4
+1
+8
+2
+1
+3
+9
+5
+4
+0
+8
+8
+7
+3
+5
+1
+1
+4
+7
+0
+1
+5
+0
+8
+0
+9
+1
+5
+5
+1
+9
+2
+6
+6
+7
+2
+2
+3
+5
+9
+3
+5
+0
+0
+6
+0
+7
+6
+5
+6
+1
+6
+4
+6
+1
+9
+6
+1
+2
+4
+7
+7
+9
+9
+3
+0
+1
+8
+9
+4
+6
+5
+4
+7
+7
+7
+9
+2
+5
+4
+0
+1
+4
+5
+6
+1
+2
+0
+3
+7
+4
+2
+9
+3
+7
+3
+2
+6
+0
+4
+6
+6
+5
+6
+1
+4
+4
+9
+2
+1
+0
+5
+0
+2
+9
+1
+4
+2
+0
+1
+5
+7
+9
+4
+7
+7
+1
+7
+3
+1
+0
+9
+1
+4
+0
+2
+0
+7
+3
+9
+0
+0
+5
+1
+9
+5
+3
+9
+1
+4
+4
+3
+4
+6
+1
+5
+0
+1
+6
+7
+3
+0
+5
+9
+5
+0
+5
+4
+2
+4
+6
+7
+4
+2
+6
+0
+5
+2
+1
+9
+4
+7
+1
+0
+7
+3
+3
+7
+1
+5
+2
+5
+9
+3
+3
+0
+7
+4
+0
+0
+8
+8
+3
+8
+8
+8
+8
+8
+8
+2
+8
+3
+3
+7
+2
+7
+9
+9
+7
+0
+6
+0
+1
+2
+9
+9
+6
+2
+3
+8
+8
+8
+7
+8
+8
+2
+3
+8
+8
+5
+2
+8
+8
+1
+9
+2
+9
+4
+8
+4
+4
+8
+8
+8
+1
+8
+8
+1
+8
+5
+1
+9
+8
+2
+8
+1
+0
+2
+0
+4
+6
+6
+1
+5
+6
+3
+6
+6
+5
+8
+4
+8
+1
+5
+9
+1
+0
+4
+0
+4
+2
+3
+5
+9
+3
+7
+2
+0
+4
+1
+2
+9
+3
+5
+7
+7
+9
+0
+7
+9
+0
+7
+5
+1
+5
+3
+9
+9
+3
+8
+6
+6
+2
+3
+2
+3
+3
+2
+2
+2
+9
+0
+2
+0
+5
+7
+3
+5
+6
+7
+0
+3
+4
+1
+4
+6
+9
+6
+1
+3
+2
+4
+7
+4
+4
+7
+5
+3
+4
+7
+1
+9
+5
+0
+0
+3
+3
+4
+6
+9
+4
+1
+2
+7
+3
+7
+6
+9
+4
+3
+4
+2
+1
+0
+9
+1
+2
+5
+1
+6
+9
+5
+3
+9
+6
+6
+5
+4
+9
+2
+7
+5
+7
+7
+2
+3
+7
+6
+0
+5
+1
+5
+5
+1
+9
+1
+3
+7
+0
+7
+5
+1
+4
+3
+3
+5
+4
+1
+7
+7
+9
+9
+2
+6
+3
+4
+0
+0
+1
+4
+5
+4
+0
+1
+0
+6
+9
+6
+1
+0
+7
+4
+4
+5
+2
+9
+6
+3
+3
+6
+2
+4
+7
+0
+2
+0
+3
+5
+6
+1
+5
+9
+4
+2
+3
+5
+7
+0
+7
+9
+3
+4
+3
+0
+7
+9
+4
+3
+6
+6
+2
+5
+5
+0
+6
+3
+2
+4
+5
+2
+5
+9
+6
+1
+2
+5
+7
+8
+9
+9
+1
+3
+5
+1
+8
+1
+1
+0
+7
+3
+3
+1
+2
+2
+9
+5
+0
+1
+7
+3
+9
+7
+4
+9
+7
+7
+0
+0
+3
+4
+9
+2
+4
+3
+6
+5
+9
+0
+9
+4
+0
+2
+4
+3
+9
+5
+3
+7
+7
+4
+2
+3
+5
+9
+6
+6
+1
+4
+6
+3
+9
+6
+0
+2
+6
+0
+1
+3
+9
+7
+3
+0
+6
+6
+7
+7
+5
+3
+1
+5
+7
+2
+2
+0
+9
+3
+2
+1
+4
+5
+5
+2
+9
+9
+7
+7
+0
+7
+0
+5
+9
+3
+3
+0
+6
+6
+1
+9
+1
+5
+3
+7
+2
+0
+0
+0
+5
+3
+0
+4
+9
+1
+4
+3
+3
+5
+2
+2
+1
+5
+7
+1
+7
+7
+1
+1
+9
+9
+5
+0
+4
+3
+4
+5
+3
+9
+6
+6
+0
+4
+3
+5
+9
+2
+2
+6
+1
+3
+7
+1
+6
+9
+4
+2
+6
+3
+9
+3
+3
+9
+8
+8
+6
+8
+8
+8
+8
+8
+8
+8
+8
+8
+5
+6
+3
+9
+2
+1
+4
+3
+4
+2
+3
+7
+1
+2
+1
+3
+0
+8
+8
+4
+5
+8
+2
+7
+1
+5
+0
+8
+3
+1
+8
+2
+9
+5
+8
+8
+2
+8
+8
+8
+6
+4
+4
+6
+3
+5
+0
+8
+0
+3
+5
+0
+1
+5
+1
+4
+8
+4
+4
+8
+9
+8
+2
+1
+8
+3
+0
+1
+0
+8
+5
+2
+7
+6
+1
+7
+2
+1
+0
+9
+1
+2
+1
+4
+7
+4
+7
+0
+6
+0
+6
+3
+9
+6
+2
+5
+6
+5
+8
+6
+9
+7
+1
+2
+5
+1
+5
+0
+9
+0
+9
+9
+4
+2
+5
+3
+9
+9
+3
+1
+1
+3
+2
+3
+0
+9
+3
+2
+5
+4
+1
+0
+4
+0
+7
+1
+2
+2
+8
+4
+6
+9
+4
+0
+5
+3
+0
+7
+0
+3
+4
+0
+1
+6
+9
+2
+7
+7
+0
+5
+7
+5
+7
+2
+6
+9
+6
+6
+5
+4
+5
+6
+4
+3
+3
+5
+2
+7
+0
+3
+0
+5
+7
+4
+9
+9
+4
+3
+5
+3
+0
+1
+9
+7
+2
+1
+6
+6
+3
+7
+0
+5
+1
+2
+2
+1
+3
+1
+3
+6
+4
+5
+5
+2
+6
+6
+3
+9
+0
+1
+7
+0
+2
+5
+7
+7
+2
+4
+0
+4
+1
+2
+4
+1
+5
+2
+2
+3
+3
+4
+4
+2
+5
+0
+0
+0
+9
+3
+3
+4
+4
+7
+7
+6
+9
+7
+3
+9
+2
+2
+4
+1
+9
+0
+6
+0
+6
+6
+2
+7
+9
+3
+8
+8
+8
+5
+8
+8
+8
+9
+0
+7
+8
+8
+8
+8
+2
+9
+0
+5
+6
+4
+8
+4
+4
+8
+8
+8
+3
+8
+2
+8
+8
+8
+2
+5
+0
+5
+1
+6
+7
+6
+3
+2
+5
+6
+9
+9
+0
+1
+4
+6
+5
+1
+7
+3
+2
+4
+3
+1
+4
+2
+9
+1
+5
+1
+2
+4
+3
+7
+4
+9
+0
+3
+0
+2
+3
+4
+5
+4
+4
+3
+0
+7
+2
+4
+5
+9
+2
+3
+4
+6
+0
+2
+0
+9
+6
+6
+2
+5
+7
+0
+0
+0
+5
+1
+6
+3
+6
+6
+3
+5
+1
+0
+6
+3
+5
+7
+6
+1
+6
+5
+5
+3
+9
+2
+1
+7
+5
+7
+5
+1
+4
+1
+3
+2
+0
+0
+1
+7
+9
+3
+5
+1
+7
+4
+0
+0
+2
+4
+5
+4
+4
+2
+4
+5
+9
+2
+6
+0
+7
+7
+6
+5
+6
+2
+1
+4
+9
+6
+4
+9
+5
+0
+3
+2
+9
+4
+7
+0
+5
+1
+1
+5
+2
+4
+9
+9
+1
+0
+3
+0
+5
+2
+0
+4
+1
+3
+8
+8
+9
+8
+8
+8
+8
+8
+0
+2
+6
+7
+1
+9
+0
+4
+6
+6
+9
+0
+6
+1
+2
+3
+7
+6
+9
+5
+8
+6
+8
+4
+2
+8
+4
+9
+5
+2
+8
+7
+8
+3
+1
+9
+8
+8
+8
+8
+8
+5
+0
+9
+0
+7
+4
+8
+4
+8
+3
+9
+2
+1
+4
+1
+9
+7
+3
+9
+1
+2
+7
+0
+9
+0
+4
+9
+8
+1
+8
+0
+5
+3
+2
+9
+6
+6
+7
+7
+9
+3
+6
+5
+0
+0
+9
+9
+1
+3
+3
+2
+5
+7
+9
+0
+0
+3
+3
+1
+8
+2
+9
+1
+1
+0
+3
+5
+6
+6
+1
+3
+5
+3
+2
+0
+4
+4
+0
+2
+0
+6
+5
+0
+9
+6
+7
+1
+1
+2
+0
+6
+6
+2
+4
+6
+4
+3
+1
+6
+7
+1
+2
+4
+1
+4
+2
+5
+9
+5
+6
+2
+7
+4
+0
+7
+2
+2
+3
+0
+0
+2
+1
+4
+9
+2
+1
+9
+7
+7
+2
+3
+9
+4
+0
+9
+5
+6
+5
+6
+7
+1
+3
+2
+2
+0
+5
+3
+1
+3
+1
+5
+6
+2
+6
+0
+9
+6
+3
+5
+4
+6
+6
+6
+1
+9
+2
+4
+2
+1
+6
+5
+3
+4
+4
+0
+1
+7
+1
+5
+5
+6
+3
+2
+9
+6
+6
+0
+5
+2
+5
+1
+9
+4
+4
+6
+4
+0
+3
+6
+9
+1
+2
+4
+6
+3
+2
+2
+9
+9
+7
+2
+0
+5
+4
+1
+3
+9
+1
+9
+0
+3
+3
+5
+9
+2
+1
+7
+3
+3
+5
+1
+9
+4
+2
+5
+0
+8
+8
+8
+8
+8
+8
+5
+8
+8
+0
+3
+0
+6
+8
+8
+7
+7
+1
+4
+8
+8
+4
+8
+8
+8
+8
+8
+8
+8
+8
+8
+4
+8
+9
+3
+6
+6
+6
+2
+1
+5
+4
+3
+7
+1
+3
+7
+8
+2
+9
+3
+8
+8
+8
+8
+1
+8
+5
+3
+7
+7
+2
+5
+5
+0
+7
+7
+9
+9
+0
+5
+3
+6
+2
+4
+5
+9
+6
+2
+7
+6
+4
+2
+4
+3
+6
+6
+2
+5
+0
+4
+0
+9
+3
+1
+0
+6
+6
+6
+5
+4
+4
+3
+4
+7
+9
+1
+1
+9
+7
+4
+3
+5
+7
+2
+0
+9
+1
+5
+2
+1
+4
+1
+7
+7
+0
+7
+3
+1
+3
+1
+4
+5
+2
+1
+7
+7
+2
+7
+5
+4
+6
+6
+3
+0
+4
+2
+6
+1
+5
+3
+7
+5
+9
+0
+1
+2
+7
+3
+0
+6
+9
+4
+5
+7
+4
+6
+6
+3
+5
+9
+0
+1
+6
+2
+4
+1
+3
+0
+2
+0
+6
+4
+7
+3
+4
+9
+4
+2
+0
+0
+5
+2
+3
+0
+6
+6
+6
+6
+7
+3
+4
+5
+4
+4
+7
+0
+6
+9
+3
+0
+5
+0
+9
+2
+2
+5
+3
+4
+2
+4
+9
+7
+1
+8
+8
+8
+3
+8
+8
+9
+8
+8
+5
+1
+3
+5
+0
+9
+1
+3
+3
+2
+8
+8
+1
+8
+6
+1
+8
+8
+2
+8
+5
+8
+4
+2
+8
+3
+7
+7
+8
+4
+6
+6
+6
+3
+9
+0
+2
+9
+0
+4
+1
+6
+4
+1
+8
+2
+2
+5
+7
+3
+1
+4
+4
+9
+7
+2
+6
+0
+9
+0
+7
+9
+4
+5
+5
+3
+9
+5
+3
+0
+7
+1
+8
+2
+9
+8
+3
+5
+2
+0
+4
+3
+9
+6
+3
+6
+2
+6
+6
+0
+7
+7
+3
+7
+8
+2
+4
+5
+4
+9
+3
+8
+8
+3
+2
+9
+5
+7
+5
+0
+0
+0
+7
+7
+2
+6
+4
+5
+2
+4
+4
+9
+5
+3
+0
+7
+9
+6
+5
+1
+6
+5
+6
+6
+0
+7
+5
+9
+7
+4
+1
+6
+9
+1
+0
+2
+0
+3
+5
+4
+6
+6
+7
+6
+6
+2
+6
+1
+3
+9
+4
+5
+4
+7
+1
+0
+9
+7
+1
+9
+0
+1
+5
+2
+3
+5
+9
+2
+1
+3
+0
+7
+9
+9
+7
+1
+1
+2
+0
+0
+0
+0
+1
+9
+6
+5
+2
+7
+3
+9
+2
+7
+2
+4
+4
+3
+4
+9
+6
+6
+2
+7
+5
+3
+7
+7
+7
+4
+2
+2
+4
+3
+3
+0
+4
+5
+9
+2
+2
+3
+3
+0
+2
+7
+9
+3
+7
+4
+6
+4
+4
+6
+4
+0
+6
+5
+1
+5
+3
+5
+8
+8
+9
+8
+8
+8
+8
+8
+8
+8
+8
+8
+7
+6
+6
+0
+9
+9
+2
+3
+4
+1
+6
+1
+9
+9
+5
+2
+2
+3
+9
+8
+0
+8
+8
+1
+8
+2
+9
+5
+3
+9
+1
+7
+4
+8
+1
+8
+8
+1
+2
+4
+0
+3
+4
+8
+7
+8
+6
+2
+2
+5
+9
+1
+4
+2
+8
+8
+7
+2
+1
+3
+3
+4
+4
+6
+6
+6
+5
+0
+3
+0
+2
+6
+1
+7
+9
+2
+3
+9
+5
+4
+9
+3
+3
+2
+2
+4
+7
+5
+4
+3
+3
+6
+6
+2
+5
+1
+9
+6
+3
+9
+1
+5
+0
+7
+9
+3
+2
+5
+4
+0
+5
+1
+1
+9
+6
+2
+2
+1
+5
+6
+9
+9
+0
+0
+3
+0
+4
+7
+7
+7
+4
+0
+3
+0
+1
+2
+9
+9
+2
+1
+3
+6
+0
+0
+2
+9
+0
+4
+2
+4
+9
+5
+5
+2
+5
+3
+6
+2
+5
+7
+5
+9
+7
+3
+6
+1
+2
+6
+0
+4
+2
+3
+4
+7
+1
+2
+6
+6
+4
+1
+8
+8
+0
+8
+0
+7
+8
+8
+8
+8
+8
+8
+0
+1
+6
+5
+5
+0
+9
+2
+1
+7
+0
+2
+0
+5
+7
+2
+8
+8
+7
+8
+8
+8
+6
+2
+8
+8
+8
+8
+7
+3
+5
+1
+0
+2
+7
+4
+8
+8
+1
+8
+8
+8
+8
+8
+0
+8
+8
+8
+1
+8
+9
+0
+5
+0
+5
+2
+3
+7
+9
+1
+1
+3
+7
+0
+8
+5
+9
+8
+4
+3
+1
+0
+6
+1
+9
+4
+8
+4
+2
+7
+3
+1
+9
+9
+6
+6
+0
+3
+2
+6
+6
+9
+6
+2
+5
+3
+3
+0
+6
+6
+8
+1
+6
+1
+7
+4
+9
+0
+1
+3
+2
+2
+0
+7
+3
+2
+5
+7
+5
+7
+9
+5
+0
+9
+0
+1
+4
+0
+3
+5
+4
+9
+4
+7
+2
+3
+1
+0
+7
+4
+6
+5
+6
+6
+0
+4
+4
+6
+4
+5
+9
+3
+7
+1
+0
+2
+0
+2
+5
+1
+2
+9
+0
+4
+0
+4
+5
+3
+4
+7
+7
+5
+6
+6
+0
+3
+1
+9
+2
+2
+5
+7
+9
+9
+2
+3
+4
+2
+4
+6
+6
+5
+1
+5
+3
+5
+6
+2
+6
+9
+5
+1
+3
+7
+0
+0
+2
+9
+6
+0
+2
+6
+3
+4
+7
+7
+2
+3
+0
+6
+2
+2
+1
+9
+5
+3
+1
+0
+9
+4
+4
+7
+4
+3
+3
+5
+9
+7
+2
+0
+7
+3
+0
+3
+5
+9
+5
+2
+2
+4
+4
+3
+4
+9
+0
+6
+7
+5
+4
+7
+9
+6
+7
+9
+5
+6
+6
+6
+9
+5
+2
+9
+9
+4
+0
+9
+8
+8
+2
+8
+8
+8
+8
+8
+5
+6
+8
+8
+2
+3
+9
+9
+3
+7
+5
+7
+6
+5
+9
+6
+3
+0
+6
+1
+1
+7
+8
+5
+6
+6
+3
+6
+9
+8
+6
+1
+8
+0
+3
+2
+0
+8
+8
+3
+2
+8
+1
+4
+9
+4
+0
+3
+8
+8
+8
+8
+9
+9
+7
+0
+4
+0
+2
+1
+9
+9
+8
+4
+7
+4
+4
+0
+7
+9
+1
+7
+8
+1
+5
+0
+4
+6
+8
+5
+1
+3
+6
+6
+3
+9
+2
+5
+5
+3
+9
+2
+3
+7
+6
+6
+4
+1
+9
+7
+6
+0
+8
+1
+6
+3
+6
+6
+3
+2
+0
+4
+7
+3
+9
+7
+1
+5
+0
+5
+1
+7
+3
+9
+6
+6
+6
+6
+9
+3
+0
+1
+6
+4
+4
+2
+2
+7
+3
+0
+0
+0
+7
+3
+3
+2
+5
+9
+3
+7
+6
+4
+9
+4
+4
+9
+0
+4
+4
+1
+9
+0
+5
+2
+0
+7
+1
+0
+5
+3
+1
+7
+9
+1
+0
+1
+4
+2
+3
+9
+3
+5
+7
+7
+8
+8
+2
+8
+8
+6
+8
+8
+8
+8
+8
+8
+7
+7
+5
+7
+0
+9
+4
+3
+3
+2
+6
+6
+1
+2
+5
+3
+6
+6
+9
+6
+8
+8
+2
+0
+8
+3
+9
+5
+5
+1
+7
+2
+8
+8
+3
+8
+2
+8
+8
+4
+8
+4
+4
+0
+4
+7
+8
+8
+4
+9
+3
+7
+1
+6
+6
+0
+5
+0
+4
+8
+7
+5
+2
+1
+9
+7
+5
+8
+4
+5
+7
+2
+2
+8
+8
+0
+8
+0
+4
+3
+1
+2
+7
+4
+8
+4
+4
+3
+4
+3
+0
+1
+7
+6
+9
+4
+1
+9
+3
+7
+5
+8
+1
+3
+6
+3
+3
+6
+7
+7
+0
+5
+9
+2
+0
+5
+6
+6
+9
+1
+5
+7
+2
+6
+3
+5
+7
+2
+6
+4
+6
+2
+3
+5
+9
+5
+0
+3
+3
+4
+3
+2
+4
+7
+5
+0
+6
+3
+3
+4
+4
+9
+4
+9
+2
+7
+5
+0
+3
+4
+4
+1
+0
+3
+5
+0
+9
+4
+2
+4
+4
+3
+6
+2
+6
+9
+4
+0
+9
+3
+1
+2
+1
+4
+5
+4
+9
+0
+4
+0
+7
+7
+1
+3
+2
+0
+3
+5
+1
+2
+2
+7
+9
+2
+7
+6
+7
+0
+1
+2
+9
+3
+0
+2
+5
+0
+6
+6
+9
+9
+1
+6
+3
+6
+1
+0
+2
+5
+6
+4
+1
+0
+4
+1
+9
+3
+2
+9
+3
+4
+6
+5
+6
+6
+7
+2
+0
+1
+0
+4
+4
+9
+4
+3
+1
+2
+0
+4
+2
+9
+4
+3
+3
+2
+2
+2
+0
+7
+5
+3
+4
+0
+9
+8
+8
+8
+8
+8
+5
+3
+9
+8
+8
+8
+6
+8
+2
+6
+9
+1
+0
+4
+6
+8
+7
+8
+8
+8
+8
+8
+2
+8
+8
+8
+3
+8
+8
+0
+8
+0
+8
+5
+3
+2
+7
+8
+6
+6
+8
+1
+5
+8
+8
+8
+8
+8
+8
+9
+3
+4
+6
+6
+5
+8
+8
+2
+1
+4
+4
+8
+7
+6
+5
+6
+0
+2
+6
+1
+9
+4
+4
+3
+3
+0
+6
+5
+7
+7
+1
+3
+4
+1
+5
+0
+9
+0
+8
+3
+2
+7
+3
+7
+9
+2
+9
+5
+5
+2
+0
+8
+0
+9
+1
+0
+4
+7
+3
+7
+9
+1
+2
+3
+3
+6
+3
+2
+5
+6
+6
+6
+2
+4
+4
+1
+4
+6
+5
+0
+6
+5
+6
+6
+3
+7
+2
+7
+7
+3
+2
+6
+9
+9
+0
+2
+0
+3
+5
+2
+2
+9
+7
+4
+0
+2
+3
+9
+1
+4
+4
+3
+4
+3
+0
+7
+6
+2
+6
+1
+6
+6
+0
+6
+0
+9
+6
+4
+5
+4
+2
+9
+4
+1
+0
+2
+9
+3
+5
+9
+3
+7
+7
+8
+8
+8
+8
+8
+8
+8
+8
+8
+5
+3
+3
+9
+7
+7
+5
+7
+4
+1
+7
+9
+6
+6
+5
+2
+9
+7
+8
+3
+2
+8
+7
+1
+6
+6
+8
+3
+0
+8
+1
+5
+9
+8
+8
+0
+8
+0
+6
+7
+5
+4
+4
+8
+4
+8
+8
+0
+6
+9
+5
+6
+0
+2
+3
+5
+9
+2
+1
+4
+7
+4
+0
+7
+7
+7
+2
+3
+8
+4
+2
+8
+0
+9
+8
+5
+5
+7
+3
+2
+6
+6
+0
+5
+1
+4
+7
+7
+2
+1
+6
+3
+9
+2
+3
+1
+8
+2
+6
+3
+9
+8
+0
+7
+0
+4
+2
+3
+9
+1
+2
+1
+1
+0
+5
+2
+9
+3
+3
+5
+2
+2
+0
+1
+5
+6
+5
+7
+0
+2
+4
+3
+4
+0
+7
+9
+6
+5
+2
+4
+9
+4
+4
+0
+3
+1
+7
+5
+6
+0
+4
+6
+2
+2
+9
+6
+7
+2
+1
+0
+6
+5
+1
+7
+9
+1
+3
+0
+5
+0
+2
+2
+1
+7
+1
+2
+3
+4
+9
+2
+2
+5
+0
+3
+0
+7
+9
+4
+9
+2
+7
+3
+3
+4
+9
+1
+9
+9
+5
+2
+1
+6
+9
+5
+0
+6
+6
+3
+3
+9
+2
+7
+1
+3
+0
+2
+0
+9
+5
+0
+2
+7
+7
+1
+7
+9
+7
+4
+1
+4
+4
+5
+4
+9
+0
+9
+6
+1
+2
+4
+5
+9
+3
+0
+2
+5
+9
+2
+6
+4
+3
+6
+4
+2
+9
+7
+1
+6
+0
+9
+0
+2
+9
+3
+3
+1
+6
+4
+7
+4
+0
+7
+8
+3
+6
+8
+8
+8
+8
+9
+7
+0
+5
+8
+2
+8
+1
+9
+0
+0
+1
+4
+8
+8
+4
+8
+8
+3
+8
+8
+8
+8
+8
+8
+4
+8
+5
+1
+3
+7
+8
+2
+2
+8
+4
+8
+9
+1
+6
+6
+8
+2
+8
+0
+3
+0
+5
+9
+1
+5
+7
+7
+3
+4
+2
+9
+0
+4
+9
+5
+1
+9
+2
+2
+7
+7
+5
+4
+6
+4
+4
+1
+2
+3
+9
+0
+1
+4
+4
+5
+6
+2
+6
+6
+8
+9
+5
+1
+1
+3
+0
+3
+0
+7
+6
+6
+6
+0
+7
+5
+5
+9
+0
+6
+4
+3
+6
+9
+3
+2
+1
+8
+7
+1
+7
+9
+3
+0
+2
+8
+9
+4
+4
+5
+7
+4
+3
+1
+9
+5
+5
+4
+2
+5
+1
+5
+2
+5
+1
+3
+7
+7
+4
+5
+9
+2
+9
+9
+1
+6
+5
+4
+5
+7
+2
+0
+0
+0
+3
+2
+9
+9
+6
+2
+5
+1
+0
+1
+2
+1
+6
+6
+4
+3
+7
+0
+9
+0
+1
+9
+5
+3
+3
+1
+2
+8
+7
+3
+9
+0
+8
+9
+8
+5
+1
+3
+9
+6
+0
+5
+4
+1
+2
+7
+3
+8
+8
+4
+5
+0
+4
+2
+3
+5
+8
+9
+1
+4
+5
+3
+4
+5
+3
+6
+0
+1
+6
+4
+9
+0
+4
+7
+0
+6
+7
+3
+9
+4
+5
+2
+4
+1
+0
+2
+7
+8
+3
+1
+0
+2
+1
+0
+5
+2
+3
+4
+7
+4
+4
+7
+4
+9
+2
+5
+1
+5
+2
+5
+0
+3
+3
+2
+5
+6
+5
+1
+2
+9
+0
+6
+3
+4
+9
+1
+7
+2
+0
+1
+3
+0
+7
+6
+9
+9
+1
+3
+3
+6
+1
+6
+9
+1
+4
+2
+3
+2
+7
+7
+1
+0
+1
+4
+3
+9
+9
+5
+2
+4
+4
+0
+4
+0
+1
+6
+6
+1
+6
+4
+9
+6
+2
+1
+6
+3
+6
+6
+1
+4
+4
+0
+4
+0
+7
+7
+2
+9
+6
+6
+4
+5
+1
+3
+3
+2
+7
+7
+5
+4
+9
+3
+3
+9
+0
+0
+1
+7
+5
+2
+7
+5
+7
+7
+2
+6
+0
+2
+2
+9
+0
+5
+0
+1
+9
+7
+9
+2
+3
+5
+6
+6
+0
+6
+1
+5
+2
+5
+6
+7
+9
+4
+0
+4
+3
+1
+4
+5
+9
+3
+6
+6
+8
+8
+3
+5
+7
+1
+8
+2
+8
+0
+3
+4
+1
+9
+5
+3
+1
+0
+8
+1
+8
+8
+8
+8
+8
+8
+1
+8
+8
+9
+8
+3
+9
+1
+7
+7
+6
+6
+2
+3
+5
+0
+8
+0
+8
+4
+8
+2
+8
+8
+8
+8
+8
+5
+1
+3
+9
+8
+8
+8
+8
+0
+5
+7
+9
+2
+3
+5
+7
+5
+8
+1
+9
+9
+5
+2
+0
+8
+8
+4
+9
+8
+3
+8
+5
+0
+6
+0
+2
+4
+3
+4
+4
+1
+7
+0
+1
+5
+6
+6
+0
+1
+0
+2
+5
+9
+1
+2
+3
+4
+6
+7
+6
+3
+3
+1
+2
+5
+5
+4
+2
+3
+0
+5
+8
+2
+9
+1
+5
+0
+2
+3
+3
+1
+9
+2
+1
+9
+7
+2
+1
+7
+9
+4
+0
+7
+0
+1
+3
+1
+9
+5
+9
+9
+1
+7
+3
+6
+7
+4
+4
+1
+1
+0
+3
+2
+2
+9
+1
+3
+2
+5
+3
+9
+7
+1
+0
+3
+3
+2
+7
+9
+1
+0
+1
+3
+6
+6
+3
+4
+5
+0
+7
+2
+9
+3
+1
+0
+2
+0
+4
+5
+9
+7
+6
+6
+0
+0
+7
+7
+1
+3
+3
+6
+6
+5
+6
+0
+9
+0
+2
+1
+6
+6
+1
+6
+9
+1
+6
+6
+2
+7
+5
+7
+0
+9
+7
+3
+3
+2
+0
+4
+9
+4
+4
+5
+3
+7
+2
+1
+9
+3
+5
+7
+5
+1
+0
+2
+0
+8
+8
+8
+7
+4
+8
+8
+8
+8
+1
+6
+3
+2
+4
+1
+4
+1
+0
+3
+0
+7
+6
+6
+1
+9
+2
+3
+0
+7
+2
+9
+4
+0
+7
+2
+3
+5
+0
+2
+0
+4
+4
+3
+2
+1
+0
+5
+0
+2
+7
+7
+3
+6
+6
+9
+6
+3
+0
+5
+9
+5
+2
+7
+6
+6
+6
+6
+9
+0
+3
+9
+2
+7
+7
+3
+7
+0
+5
+9
+1
+2
+1
+3
+3
+1
+9
+9
+5
+0
+2
+3
+9
+4
+4
+2
+2
+1
+5
+2
+9
+3
+3
+1
+2
+2
+7
+7
+9
+2
+7
+5
+5
+2
+4
+3
+6
+6
+3
+1
+7
+6
+6
+0
+4
+9
+0
+2
+3
+6
+0
+1
+5
+9
+6
+6
+4
+5
+1
+6
+6
+9
+1
+6
+4
+1
+0
+1
+0
+9
+2
+4
+1
+4
+7
+2
+5
+3
+0
+1
+0
+5
+2
+9
+6
+5
+6
+6
+7
+1
+0
+2
+6
+3
+7
+7
+2
+2
+6
+6
+1
+3
+5
+0
+9
+5
+7
+5
+6
+0
+6
+4
+3
+9
+4
+5
+5
+7
+7
+3
+9
+9
+9
+9
+5
+3
+5
+0
+3
+5
+1
+4
+7
+2
+0
+7
+4
+9
+7
+7
+8
+8
+8
+8
+8
+0
+3
+8
+8
+6
+9
+1
+8
+4
+6
+0
+2
+2
+1
+5
+8
+8
+8
+8
+8
+2
+8
+8
+8
+8
+3
+8
+6
+6
+9
+6
+7
+3
+0
+1
+5
+4
+9
+2
+2
+3
+1
+8
+2
+0
+1
+8
+7
+3
+3
+4
+8
+8
+4
+8
+1
+3
+3
+8
+4
+6
+8
+1
+5
+3
+6
+6
+7
+9
+2
+7
+8
+3
+3
+2
+0
+9
+4
+2
+4
+8
+3
+8
+2
+7
+5
+4
+0
+4
+4
+5
+3
+9
+2
+4
+7
+7
+9
+5
+3
+1
+0
+2
+2
+3
+5
+4
+5
+9
+0
+2
+0
+3
+9
+0
+6
+6
+7
+6
+5
+2
+9
+1
+3
+7
+1
+7
+6
+6
+7
+9
+3
+0
+6
+6
+1
+4
+9
+9
+3
+4
+6
+6
+7
+3
+9
+7
+3
+2
+5
+4
+1
+5
+9
+3
+7
+0
+3
+7
+1
+4
+4
+1
+4
+4
+3
+2
+9
+7
+1
+4
+5
+7
+1
+0
+2
+1
+9
+9
+3
+2
+3
+4
+1
+6
+6
+0
+4
+2
+9
+1
+5
+9
+7
+7
+3
+4
+3
+5
+4
+1
+2
+5
+3
+1
+9
+0
+7
+7
+7
+2
+1
+0
+9
+4
+2
+6
+0
+3
+7
+7
+5
+9
+0
+4
+1
+5
+6
+6
+2
+9
+6
+7
+2
+6
+5
+7
+3
+9
+1
+4
+6
+2
+0
+1
+3
+9
+5
+2
+5
+1
+9
+2
+6
+6
+8
+8
+8
+8
+8
+4
+8
+8
+4
+7
+8
+8
+0
+5
+7
+7
+4
+0
+5
+3
+9
+3
+5
+1
+3
+5
+4
+0
+9
+8
+8
+0
+8
+0
+8
+1
+9
+9
+2
+3
+6
+6
+3
+0
+8
+8
+1
+3
+8
+1
+8
+8
+2
+0
+6
+5
+7
+8
+8
+7
+5
+0
+5
+1
+7
+2
+9
+7
+9
+4
+1
+0
+6
+0
+9
+6
+5
+1
+2
+0
+7
+6
+9
+2
+1
+5
+6
+6
+3
+1
+9
+0
+7
+4
+4
+3
+4
+2
+7
+9
+6
+1
+5
+3
+3
+7
+2
+9
+7
+7
+2
+4
+1
+4
+7
+0
+4
+1
+5
+3
+2
+5
+9
+9
+1
+2
+7
+7
+9
+5
+0
+4
+0
+4
+4
+1
+5
+3
+2
+9
+7
+4
+7
+7
+4
+0
+3
+2
+6
+5
+0
+1
+9
+7
+3
+9
+3
+2
+0
+5
+6
+6
+3
+1
+3
+7
+5
+6
+9
+9
+2
+7
+6
+5
+7
+6
+9
+1
+4
+2
+4
+0
+5
+3
+1
+3
+1
+7
+7
+2
+7
+4
+1
+3
+4
+5
+9
+2
+6
+5
+5
+1
+6
+0
+6
+7
+2
+9
+5
+3
+2
+4
+1
+4
+4
+9
+4
+3
+3
+1
+2
+8
+8
+8
+8
+8
+8
+0
+8
+2
+5
+8
+7
+5
+4
+3
+3
+0
+7
+7
+8
+8
+8
+8
+8
+8
+8
+8
+6
+0
+5
+8
+1
+9
+1
+8
+8
+2
+8
+3
+7
+6
+3
+1
+0
+6
+6
+6
+4
+8
+2
+8
+6
+6
+6
+4
+9
+4
+4
+2
+2
+8
+7
+7
+6
+3
+0
+6
+4
+2
+9
+1
+1
+3
+5
+7
+8
+5
+9
+5
+9
+9
+1
+4
+8
+1
+0
+5
+0
+9
+3
+2
+1
+0
+1
+4
+6
+6
+3
+2
+2
+9
+6
+0
+4
+0
+1
+5
+9
+9
+7
+4
+3
+1
+6
+1
+5
+8
+0
+3
+1
+5
+3
+0
+7
+0
+7
+5
+2
+5
+3
+5
+2
+9
+1
+7
+7
+1
+5
+0
+3
+0
+4
+5
+1
+3
+5
+0
+4
+9
+2
+5
+6
+7
+2
+4
+9
+9
+5
+0
+5
+3
+9
+4
+2
+7
+4
+6
+4
+2
+9
+1
+5
+9
+0
+4
+1
+3
+9
+6
+5
+7
+2
+4
+0
+4
+9
+1
+3
+9
+1
+2
+2
+7
+9
+9
+4
+2
+0
+1
+0
+2
+5
+9
+0
+5
+1
+5
+0
+7
+4
+3
+7
+1
+2
+7
+5
+6
+0
+3
+1
+6
+5
+2
+5
+9
+6
+1
+7
+7
+0
+2
+2
+9
+7
+3
+5
+1
+3
+1
+0
+1
+3
+4
+5
+4
+4
+7
+4
+9
+0
+3
+0
+6
+9
+6
+4
+5
+0
+0
+8
+3
+8
+8
+5
+8
+8
+8
+4
+3
+8
+9
+9
+6
+5
+3
+7
+7
+3
+6
+0
+0
+2
+4
+3
+4
+2
+1
+3
+7
+6
+2
+8
+1
+8
+9
+2
+8
+8
+1
+1
+2
+8
+9
+8
+2
+8
+8
+8
+3
+7
+9
+8
+8
+8
+0
+8
+0
+8
+5
+4
+5
+7
+2
+9
+0
+8
+4
+1
+2
+0
+8
+0
+7
+6
+6
+3
+4
+1
+7
+9
+1
+8
+9
+3
+8
+2
+4
+1
+4
+4
+3
+2
+4
+9
+1
+4
+3
+0
+5
+3
+1
+9
+7
+2
+1
+5
+6
+5
+1
+5
+4
+6
+2
+4
+5
+7
+6
+6
+5
+0
+3
+2
+4
+0
+6
+9
+0
+7
+0
+6
+3
+2
+5
+9
+5
+2
+2
+0
+3
+3
+2
+9
+5
+0
+2
+1
+7
+3
+0
+9
+4
+9
+5
+0
+1
+1
+7
+3
+9
+2
+1
+7
+2
+2
+0
+3
+1
+1
+6
+5
+3
+5
+2
+9
+9
+9
+4
+4
+7
+4
+1
+3
+6
+5
+0
+2
+4
+9
+3
+7
+7
+8
+8
+8
+8
+8
+8
+8
+8
+3
+8
+8
+8
+7
+3
+1
+0
+4
+0
+6
+1
+9
+3
+5
+9
+1
+5
+2
+0
+8
+3
+5
+8
+8
+6
+7
+9
+8
+3
+6
+2
+0
+4
+5
+9
+6
+1
+3
+0
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+9
+7
+3
+0
+7
+9
+8
+1
+9
+8
+1
+8
+2
+9
+7
+0
+9
+2
+5
+8
+8
+1
+2
+0
+4
+0
+2
+4
+8
+3
+5
+8
+6
+1
+4
+2
+3
+4
+1
+8
+5
+6
+6
+0
+1
+7
+4
+4
+7
+2
+2
+7
+7
+9
+2
+6
+6
+4
+1
+6
+3
+9
+7
+2
+0
+6
+6
+6
+0
+5
+0
+3
+1
+7
+7
+4
+7
+2
+3
+1
+9
+4
+5
+1
+3
+9
+9
+3
+0
+0
+0
+5
+3
+1
+9
+3
+7
+6
+6
+7
+0
+0
+5
+3
+6
+9
+7
+1
+3
+7
+7
+3
+2
+9
+1
+4
+3
+4
+5
+5
+0
+9
+0
+1
+4
+7
+2
+4
+7
+9
+9
+2
+4
+5
+3
+0
+2
+0
+9
+7
+2
+6
+6
+7
+4
+9
+5
+9
+3
+2
+2
+3
+4
+5
+2
+6
+6
+7
+2
+7
+7
+1
+9
+5
+0
+6
+6
+2
+6
+7
+9
+7
+1
+1
+4
+9
+3
+1
+9
+4
+6
+2
+3
+3
+0
+3
+7
+7
+5
+5
+3
+0
+4
+3
+1
+2
+4
+5
+4
+4
+1
+1
+0
+3
+2
+2
+1
+1
+5
+2
+5
+1
+5
+7
+1
+9
+3
+5
+6
+7
+0
+1
+0
+9
+3
+4
+2
+5
+1
+8
+8
+8
+8
+8
+7
+8
+8
+5
+8
+2
+8
+3
+1
+4
+2
+9
+9
+5
+9
+1
+5
+1
+0
+6
+0
+6
+3
+0
+2
+9
+5
+5
+7
+1
+8
+6
+6
+7
+6
+0
+8
+6
+5
+8
+6
+8
+4
+8
+8
+8
+8
+2
+8
+9
+7
+8
+8
+8
+1
+1
+3
+0
+6
+0
+5
+7
+4
+8
+3
+2
+1
+3
+9
+5
+2
+1
+3
+9
+2
+7
+7
+5
+7
+2
+3
+9
+4
+8
+6
+4
+8
+7
+7
+9
+5
+5
+4
+4
+1
+4
+5
+2
+3
+6
+0
+6
+5
+7
+7
+1
+2
+6
+1
+7
+6
+5
+2
+6
+9
+1
+2
+1
+0
+0
+7
+9
+1
+1
+4
+4
+7
+5
+5
+1
+5
+0
+3
+3
+1
+4
+1
+9
+5
+7
+7
+3
+4
+1
+6
+9
+3
+4
+1
+3
+2
+7
+7
+9
+9
+4
+6
+1
+0
+3
+2
+6
+9
+7
+4
+4
+6
+6
+7
+9
+6
+1
+3
+0
+6
+0
+1
+9
+2
+5
+3
+5
+1
+2
+0
+7
+9
+6
+1
+5
+3
+9
+2
+0
+0
+7
+7
+7
+3
+3
+4
+7
+5
+5
+0
+2
+4
+3
+4
+4
+9
+4
+6
+0
+6
+2
+8
+3
+8
+8
+8
+8
+8
+6
+6
+3
+4
+8
+4
+1
+8
+9
+1
+5
+9
+8
+8
+8
+0
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+7
+1
+0
+4
+5
+9
+4
+5
+1
+8
+6
+1
+6
+6
+7
+1
+8
+8
+6
+8
+8
+6
+1
+8
+5
+8
+8
+5
+8
+9
+6
+6
+3
+2
+9
+6
+0
+5
+5
+3
+3
+0
+9
+2
+7
+7
+5
+4
+7
+8
+9
+5
+2
+9
+8
+1
+2
+4
+9
+8
+4
+1
+2
+3
+1
+0
+3
+9
+5
+1
+4
+5
+7
+7
+6
+2
+0
+4
+1
+3
+3
+5
+9
+1
+2
+0
+6
+7
+2
+6
+3
+6
+7
+2
+2
+1
+4
+3
+2
+7
+0
+6
+5
+2
+7
+3
+3
+9
+1
+5
+6
+4
+4
+6
+3
+9
+2
+1
+1
+3
+7
+3
+5
+0
+1
+2
+9
+3
+9
+1
+5
+6
+0
+2
+9
+7
+1
+3
+3
+1
+6
+1
+9
+1
+6
+6
+3
+4
+4
+6
+1
+7
+5
+0
+3
+5
+7
+4
+0
+9
+6
+3
+7
+7
+3
+2
+2
+4
+0
+7
+0
+2
+5
+0
+5
+9
+0
+3
+1
+5
+1
+0
+7
+9
+7
+5
+6
+4
+6
+6
+9
+9
+1
+2
+7
+3
+9
+7
+2
+5
+1
+6
+1
+3
+9
+4
+1
+6
+1
+4
+7
+7
+0
+6
+9
+9
+5
+1
+1
+3
+9
+5
+4
+0
+6
+2
+8
+8
+8
+8
+2
+8
+4
+0
+8
+0
+8
+9
+5
+2
+4
+0
+4
+0
+9
+7
+3
+9
+2
+4
+5
+6
+4
+0
+8
+0
+8
+1
+5
+7
+8
+8
+3
+8
+9
+2
+8
+4
+4
+5
+2
+1
+0
+0
+8
+8
+8
+8
+1
+8
+8
+8
+8
+8
+8
+0
+3
+7
+5
+8
+0
+9
+7
+3
+3
+1
+9
+2
+6
+6
+0
+6
+2
+8
+9
+8
+7
+6
+0
+7
+3
+8
+9
+5
+5
+8
+8
+1
+7
+6
+2
+9
+4
+1
+6
+6
+2
+5
+3
+9
+2
+0
+1
+3
+0
+5
+9
+4
+8
+2
+4
+3
+4
+8
+0
+9
+0
+5
+2
+4
+9
+3
+3
+0
+0
+0
+8
+2
+9
+4
+4
+9
+3
+2
+5
+0
+5
+3
+7
+9
+4
+2
+0
+0
+6
+3
+3
+5
+7
+7
+2
+6
+5
+0
+3
+1
+7
+7
+2
+3
+9
+9
+7
+0
+5
+1
+9
+1
+2
+1
+0
+0
+7
+0
+5
+3
+6
+6
+7
+7
+6
+1
+6
+0
+1
+3
+2
+0
+0
+6
+9
+7
+6
+1
+5
+2
+2
+7
+9
+5
+2
+6
+6
+6
+1
+7
+9
+5
+5
+3
+4
+1
+4
+5
+9
+1
+8
+7
+8
+8
+8
+8
+8
+9
+0
+8
+8
+2
+5
+4
+4
+9
+2
+7
+1
+4
+8
+8
+8
+8
+8
+2
+8
+8
+8
+8
+8
+9
+8
+1
+7
+5
+9
+0
+8
+1
+6
+6
+5
+6
+9
+7
+1
+5
+2
+6
+0
+3
+0
+2
+6
+4
+5
+8
+8
+3
+7
+7
+0
+9
+5
+7
+9
+1
+1
+0
+2
+8
+8
+6
+2
+9
+5
+1
+6
+0
+8
+1
+0
+2
+5
+6
+7
+7
+1
+5
+9
+4
+3
+4
+4
+8
+6
+6
+7
+6
+5
+4
+1
+0
+4
+0
+5
+9
+7
+3
+3
+4
+7
+0
+9
+9
+1
+2
+3
+5
+5
+4
+4
+9
+4
+2
+5
+1
+5
+4
+1
+9
+4
+1
+2
+1
+3
+7
+0
+2
+6
+6
+7
+7
+9
+4
+7
+0
+2
+6
+5
+0
+9
+5
+6
+6
+7
+2
+0
+7
+3
+9
+0
+4
+0
+4
+6
+1
+4
+9
+5
+7
+2
+5
+0
+2
+3
+5
+6
+6
+2
+3
+0
+5
+0
+7
+4
+7
+4
+0
+7
+5
+3
+2
+0
+1
+9
+6
+9
+4
+3
+4
+1
+5
+7
+1
+2
+7
+6
+1
+6
+6
+5
+3
+0
+2
+3
+5
+1
+4
+9
+7
+4
+5
+3
+5
+6
+5
+9
+4
+1
+3
+7
+7
+2
+0
+9
+9
+2
+3
+3
+5
+5
+4
+1
+0
+4
+3
+2
+7
+4
+7
+9
+6
+6
+7
+4
+2
+1
+1
+8
+8
+8
+8
+8
+3
+6
+7
+8
+8
+8
+8
+6
+6
+3
+2
+5
+9
+6
+0
+7
+0
+3
+1
+9
+9
+4
+3
+8
+8
+9
+8
+3
+8
+0
+7
+0
+8
+9
+8
+3
+5
+1
+4
+8
+8
+8
+8
+8
+7
+8
+8
+2
+8
+9
+8
+6
+6
+5
+8
+6
+9
+6
+1
+1
+2
+5
+8
+7
+9
+1
+7
+4
+1
+2
+1
+4
+1
+2
+8
+5
+8
+8
+8
+1
+9
+0
+2
+0
+1
+8
+5
+1
+4
+4
+0
+4
+7
+9
+7
+5
+1
+5
+4
+6
+6
+9
+6
+9
+9
+0
+4
+6
+5
+4
+2
+4
+9
+7
+6
+3
+2
+5
+1
+5
+6
+1
+3
+6
+2
+3
+0
+0
+0
+4
+5
+4
+7
+3
+2
+1
+0
+2
+3
+7
+1
+9
+7
+2
+5
+0
+0
+2
+0
+9
+5
+7
+5
+7
+7
+5
+3
+3
+9
+1
+9
+0
+3
+0
+6
+1
+9
+7
+7
+5
+4
+0
+4
+4
+9
+4
+6
+4
+6
+2
+3
+5
+4
+2
+5
+6
+4
+9
+9
+0
+5
+7
+2
+1
+7
+9
+1
+5
+1
+5
+0
+2
+3
+9
+5
+2
+4
+1
+4
+4
+5
+4
+9
+7
+6
+2
+8
+8
+8
+6
+3
+8
+8
+8
+1
+9
+4
+0
+4
+4
+8
+6
+6
+6
+6
+8
+8
+8
+8
+8
+8
+8
+8
+8
+5
+8
+8
+2
+7
+9
+8
+8
+2
+7
+7
+3
+0
+9
+8
+1
+3
+5
+8
+4
+8
+9
+8
+7
+7
+8
+4
+3
+8
+9
+2
+6
+0
+6
+6
+7
+7
+4
+9
+4
+2
+5
+1
+6
+5
+0
+0
+0
+7
+4
+3
+6
+6
+2
+0
+6
+0
+7
+3
+4
+8
+5
+2
+1
+5
+1
+0
+3
+9
+5
+1
+7
+4
+9
+3
+6
+6
+1
+8
+0
+2
+9
+3
+3
+1
+0
+0
+6
+0
+9
+6
+1
+9
+2
+5
+4
+1
+9
+0
+6
+7
+3
+6
+2
+2
+7
+9
+3
+1
+3
+4
+7
+4
+0
+9
+3
+4
+4
+5
+4
+4
+7
+7
+0
+1
+5
+2
+2
+5
+9
+1
+2
+3
+7
+7
+2
+4
+4
+5
+4
+2
+3
+0
+9
+7
+5
+6
+0
+9
+3
+7
+0
+6
+2
+9
+6
+3
+0
+5
+4
+7
+9
+2
+2
+6
+4
+0
+5
+0
+6
+1
+1
+2
+6
+4
+9
+4
+1
+0
+6
+5
+7
+5
+3
+4
+2
+0
+4
+0
+5
+2
+1
+5
+1
+2
+7
+3
+5
+1
+3
+0
+4
+6
+2
+3
+1
+9
+3
+1
+5
+0
+7
+1
+6
+9
+1
+5
+4
+0
+1
+0
+2
+9
+5
+1
+2
+2
+9
+0
+6
+3
+8
+8
+8
+8
+8
+4
+8
+8
+7
+8
+8
+5
+0
+2
+7
+9
+1
+0
+1
+2
+9
+6
+2
+4
+7
+7
+6
+1
+0
+8
+5
+2
+2
+1
+3
+8
+2
+9
+0
+6
+1
+3
+5
+4
+6
+8
+8
+6
+0
+8
+8
+8
+9
+8
+8
+8
+8
+8
+3
+7
+9
+9
+6
+2
+5
+3
+5
+1
+3
+0
+7
+7
+8
+2
+1
+5
+9
+9
+4
+8
+4
+3
+3
+1
+5
+9
+2
+4
+6
+4
+4
+2
+6
+4
+2
+1
+4
+3
+3
+0
+7
+0
+1
+4
+5
+1
+7
+1
+5
+1
+8
+1
+9
+2
+5
+9
+1
+5
+1
+0
+9
+3
+3
+7
+3
+8
+1
+5
+5
+9
+1
+2
+7
+1
+0
+7
+2
+9
+6
+6
+1
+5
+0
+0
+6
+0
+1
+9
+3
+7
+6
+7
+9
+9
+2
+1
+6
+6
+4
+2
+0
+7
+6
+2
+2
+0
+9
+6
+2
+9
+0
+3
+1
+2
+6
+4
+7
+2
+5
+3
+4
+4
+7
+1
+1
+9
+2
+4
+4
+0
+9
+5
+5
+9
+7
+1
+2
+3
+4
+0
+4
+6
+1
+5
+0
+2
+3
+0
+7
+0
+7
+7
+5
+6
+6
+6
+6
+4
+2
+0
+8
+5
+8
+1
+8
+8
+8
+8
+9
+8
+1
+2
+8
+6
+4
+7
+9
+1
+7
+9
+8
+8
+8
+8
+0
+2
+8
+8
+8
+8
+8
+3
+5
+9
+2
+8
+6
+6
+1
+6
+7
+3
+3
+2
+2
+0
+8
+8
+2
+8
+3
+6
+5
+0
+8
+4
+9
+9
+4
+8
+8
+8
+7
+1
+9
+5
+2
+5
+3
+7
+9
+2
+2
+9
+7
+4
+3
+5
+4
+5
+1
+3
+5
+4
+7
+2
+4
+0
+4
+3
+7
+7
+6
+6
+6
+6
+5
+1
+2
+3
+3
+5
+0
+1
+0
+4
+6
+5
+2
+0
+1
+6
+6
+6
+3
+0
+5
+1
+9
+7
+1
+5
+0
+4
+1
+4
+9
+0
+0
+5
+2
+1
+3
+9
+0
+7
+0
+6
+1
+7
+3
+1
+6
+2
+0
+6
+4
+1
+4
+5
+6
+6
+7
+2
+0
+7
+0
+2
+5
+0
+6
+6
+6
+6
+7
+4
+4
+7
+4
+1
+9
+5
+5
+9
+3
+4
+2
+3
+9
+3
+2
+7
+1
+0
+0
+4
+9
+3
+4
+9
+2
+5
+7
+5
+1
+9
+4
+3
+7
+0
+5
+5
+9
+9
+6
+3
+6
+6
+1
+0
+5
+3
+6
+5
+3
+7
+6
+2
+6
+0
+0
+0
+3
+4
+3
+6
+7
+4
+6
+3
+2
+1
+9
+4
+0
+5
+0
+7
+1
+7
+7
+1
+0
+9
+5
+1
+3
+4
+1
+4
+4
+9
+1
+3
+0
+5
+0
+2
+7
+1
+8
+8
+8
+8
+8
+4
+8
+8
+0
+8
+8
+9
+6
+1
+6
+2
+7
+3
+9
+7
+1
+9
+1
+4
+5
+3
+0
+1
+7
+8
+8
+7
+8
+8
+5
+3
+4
+1
+2
+5
+8
+7
+8
+3
+3
+7
+8
+5
+1
+8
+0
+9
+2
+6
+8
+8
+8
+8
+6
+9
+4
+0
+3
+8
+9
+6
+2
+3
+5
+6
+2
+0
+7
+0
+7
+7
+6
+4
+7
+7
+9
+5
+6
+3
+3
+2
+8
+4
+5
+4
+4
+0
+5
+3
+0
+4
+0
+9
+5
+1
+4
+7
+2
+5
+9
+9
+1
+4
+2
+1
+3
+2
+2
+2
+0
+1
+0
+3
+3
+7
+1
+2
+7
+7
+9
+2
+7
+1
+0
+2
+6
+5
+9
+3
+1
+9
+7
+7
+0
+7
+5
+1
+3
+7
+4
+5
+0
+2
+1
+7
+3
+9
+2
+6
+4
+3
+9
+2
+4
+9
+3
+4
+1
+3
+9
+6
+2
+0
+3
+0
+7
+6
+9
+3
+3
+5
+6
+4
+4
+6
+4
+3
+0
+9
+0
+2
+7
+4
+6
+9
+1
+3
+3
+0
+6
+5
+7
+4
+4
+3
+4
+5
+2
+0
+1
+9
+5
+2
+3
+5
+0
+2
+7
+7
+7
+1
+5
+4
+4
+4
+5
+2
+5
+3
+7
+7
+9
+1
+0
+5
+2
+5
+6
+6
+2
+4
+0
+0
+3
+4
+5
+4
+4
+2
+2
+9
+5
+0
+1
+2
+9
+5
+5
+8
+8
+2
+2
+4
+4
+8
+3
+9
+1
+7
+5
+1
+8
+4
+0
+8
+8
+8
+8
+8
+8
+8
+7
+7
+0
+8
+6
+6
+8
+6
+3
+9
+0
+0
+2
+7
+1
+3
+6
+1
+5
+1
+6
+2
+6
+0
+3
+6
+4
+8
+4
+7
+6
+5
+5
+9
+2
+8
+8
+5
+8
+3
+6
+7
+6
+6
+2
+4
+9
+1
+4
+2
+3
+0
+5
+0
+9
+4
+1
+9
+1
+8
+7
+1
+5
+7
+9
+5
+3
+1
+4
+8
+9
+2
+7
+1
+7
+5
+2
+0
+9
+9
+1
+2
+5
+4
+3
+4
+6
+9
+7
+3
+0
+7
+6
+6
+2
+1
+5
+3
+6
+6
+2
+5
+0
+2
+0
+3
+3
+2
+1
+9
+7
+2
+2
+3
+1
+5
+6
+1
+5
+0
+5
+2
+0
+4
+5
+4
+4
+7
+6
+5
+6
+6
+9
+9
+0
+6
+7
+7
+9
+2
+3
+6
+6
+4
+2
+4
+4
+1
+3
+5
+4
+5
+7
+2
+9
+6
+3
+9
+7
+5
+5
+3
+9
+0
+3
+4
+2
+1
+5
+3
+7
+9
+2
+1
+4
+1
+2
+2
+0
+9
+7
+7
+3
+4
+1
+2
+7
+3
+3
+0
+5
+4
+7
+6
+2
+9
+7
+7
+6
+0
+4
+1
+0
+2
+8
+8
+8
+8
+2
+8
+8
+8
+8
+5
+8
+8
+6
+4
+4
+6
+4
+6
+3
+5
+0
+7
+2
+4
+3
+4
+4
+7
+8
+4
+0
+7
+0
+8
+3
+9
+6
+8
+8
+2
+2
+1
+4
+9
+6
+6
+7
+3
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+3
+5
+6
+5
+2
+6
+8
+3
+1
+2
+2
+1
+5
+0
+9
+0
+7
+7
+8
+8
+7
+8
+1
+3
+3
+9
+8
+1
+8
+8
+7
+6
+5
+1
+5
+8
+4
+0
+9
+0
+4
+2
+7
+6
+7
+5
+2
+6
+6
+3
+3
+2
+1
+4
+5
+2
+4
+6
+4
+0
+6
+1
+9
+3
+7
+4
+6
+6
+8
+5
+7
+9
+0
+2
+0
+4
+7
+0
+2
+5
+4
+3
+0
+2
+6
+6
+9
+2
+2
+3
+5
+8
+7
+7
+0
+9
+5
+3
+9
+6
+2
+9
+1
+6
+5
+3
+0
+7
+6
+5
+5
+1
+4
+2
+3
+6
+6
+1
+2
+2
+5
+6
+9
+2
+0
+9
+0
+1
+7
+3
+9
+9
+3
+4
+7
+0
+1
+3
+5
+3
+7
+7
+2
+5
+0
+0
+9
+2
+0
+9
+1
+5
+1
+4
+7
+4
+3
+6
+4
+6
+0
+1
+5
+9
+1
+2
+3
+1
+7
+0
+0
+0
+6
+2
+3
+4
+4
+6
+1
+3
+6
+6
+5
+7
+6
+7
+4
+2
+3
+1
+1
+0
+2
+5
+7
+5
+2
+3
+3
+0
+9
+2
+1
+9
+0
+3
+0
+5
+9
+5
+4
+9
+5
+0
+3
+2
+9
+7
+1
+2
+3
+4
+6
+6
+6
+6
+8
+3
+6
+1
+9
+8
+2
+5
+0
+7
+2
+2
+3
+1
+5
+2
+5
+3
+4
+2
+9
+5
+8
+9
+8
+3
+1
+4
+9
+0
+7
+6
+0
+3
+2
+4
+9
+9
+1
+9
+4
+1
+0
+6
+0
+9
+6
+4
+4
+6
+0
+5
+1
+6
+6
+6
+7
+7
+5
+7
+3
+2
+0
+1
+6
+6
+6
+6
+7
+7
+3
+5
+5
+0
+5
+2
+1
+9
+5
+2
+5
+0
+1
+3
+2
+9
+0
+7
+0
+2
+7
+1
+5
+6
+5
+4
+7
+0
+9
+4
+9
+3
+4
+2
+1
+5
+9
+0
+6
+0
+6
+6
+4
+7
+9
+0
+7
+3
+3
+7
+6
+4
+9
+6
+4
+5
+1
+0
+4
+0
+5
+1
+1
+3
+3
+4
+9
+4
+1
+0
+4
+1
+2
+6
+5
+9
+4
+0
+4
+6
+3
+2
+2
+9
+6
+7
+5
+4
+3
+0
+3
+2
+0
+4
+5
+3
+9
+7
+3
+1
+2
+1
+1
+3
+9
+4
+9
+5
+6
+2
+1
+3
+0
+7
+2
+9
+5
+0
+4
+5
+9
+1
+4
+7
+1
+7
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+9
+1
+7
+4
+2
+4
+5
+7
+1
+6
+6
+0
+5
+0
+4
+4
+3
+8
+1
+7
+0
+6
+6
+8
+9
+4
+5
+2
+6
+7
+7
+8
+0
+8
+5
+6
+2
+8
+8
+8
+9
+8
+8
+3
+8
+8
+5
+8
+9
+7
+7
+9
+0
+1
+5
+8
+3
+6
+4
+1
+6
+4
+1
+5
+0
+6
+6
+9
+8
+8
+8
+5
+7
+8
+0
+9
+2
+2
+1
+8
+3
+1
+4
+4
+7
+5
+2
+1
+3
+0
+1
+9
+9
+7
+7
+2
+5
+7
+0
+2
+7
+1
+4
+4
+2
+5
+1
+3
+0
+6
+6
+8
+1
+0
+2
+5
+9
+3
+1
+2
+4
+9
+6
+0
+9
+0
+6
+2
+7
+1
+3
+7
+9
+0
+6
+6
+6
+2
+3
+6
+1
+2
+4
+0
+7
+6
+2
+9
+6
+5
+4
+6
+0
+7
+0
+2
+3
+3
+1
+3
+5
+9
+5
+6
+4
+3
+4
+4
+2
+5
+7
+5
+3
+3
+5
+7
+5
+2
+6
+5
+3
+1
+5
+6
+0
+0
+2
+1
+3
+7
+1
+7
+7
+4
+0
+7
+1
+3
+5
+2
+9
+2
+5
+4
+0
+4
+7
+9
+2
+2
+0
+4
+5
+9
+2
+1
+9
+7
+2
+0
+4
+9
+6
+4
+5
+1
+5
+2
+0
+1
+0
+2
+9
+6
+6
+5
+6
+9
+5
+3
+7
+2
+2
+1
+3
+6
+9
+3
+6
+6
+4
+7
+7
+1
+9
+0
+9
+4
+6
+6
+6
+9
+3
+5
+4
+7
+9
+4
+1
+9
+9
+3
+9
+8
+8
+8
+5
+7
+8
+8
+8
+8
+8
+8
+4
+8
+8
+4
+3
+3
+5
+2
+4
+8
+8
+8
+8
+8
+8
+8
+8
+0
+8
+8
+8
+2
+5
+0
+1
+0
+4
+4
+0
+4
+2
+1
+9
+7
+2
+7
+4
+4
+0
+5
+9
+1
+9
+0
+5
+1
+4
+1
+9
+6
+3
+6
+6
+9
+0
+4
+9
+2
+5
+1
+5
+9
+1
+6
+6
+5
+0
+7
+3
+3
+6
+4
+9
+1
+0
+2
+6
+9
+5
+9
+9
+2
+3
+7
+1
+2
+5
+1
+0
+0
+1
+4
+3
+7
+9
+3
+7
+1
+5
+0
+3
+1
+5
+5
+9
+7
+1
+2
+3
+7
+7
+4
+1
+4
+6
+5
+2
+2
+3
+3
+1
+7
+7
+0
+7
+0
+6
+3
+5
+5
+4
+9
+6
+0
+9
+3
+4
+5
+6
+2
+6
+9
+9
+7
+2
+0
+1
+1
+4
+2
+5
+3
+1
+9
+4
+0
+3
+5
+2
+1
+7
+6
+9
+9
+6
+0
+2
+5
+1
+9
+5
+2
+3
+1
+7
+3
+6
+0
+1
+2
+3
+4
+6
+3
+2
+8
+8
+8
+4
+2
+8
+7
+8
+3
+8
+8
+8
+6
+2
+0
+6
+0
+9
+1
+0
+0
+3
+2
+7
+9
+4
+4
+1
+8
+5
+9
+2
+2
+1
+7
+0
+5
+0
+9
+3
+1
+2
+8
+4
+8
+8
+8
+8
+3
+5
+8
+8
+6
+8
+9
+6
+3
+0
+8
+8
+7
+7
+9
+3
+6
+6
+3
+8
+1
+2
+0
+9
+0
+2
+3
+0
+6
+4
+6
+3
+4
+9
+7
+1
+8
+5
+2
+4
+8
+9
+1
+5
+0
+4
+2
+1
+7
+6
+9
+2
+5
+9
+1
+6
+2
+1
+9
+1
+6
+9
+5
+6
+7
+2
+4
+7
+4
+9
+1
+3
+5
+1
+0
+4
+7
+7
+0
+6
+2
+3
+5
+2
+2
+1
+4
+5
+2
+3
+9
+7
+7
+2
+4
+5
+1
+2
+3
+7
+0
+1
+2
+3
+6
+6
+9
+1
+3
+0
+1
+7
+2
+1
+9
+2
+6
+6
+5
+0
+1
+0
+6
+9
+7
+2
+5
+4
+6
+4
+6
+9
+4
+9
+2
+1
+5
+3
+2
+9
+4
+1
+6
+6
+9
+5
+5
+3
+2
+4
+4
+5
+4
+2
+7
+7
+3
+2
+7
+5
+5
+3
+0
+0
+3
+0
+2
+4
+9
+4
+2
+3
+7
+6
+9
+1
+0
+3
+2
+5
+3
+0
+1
+9
+2
+1
+4
+3
+3
+7
+9
+1
+1
+5
+0
+0
+3
+2
+9
+0
+5
+1
+5
+4
+1
+0
+2
+9
+2
+1
+0
+3
+9
+5
+3
+2
+6
+6
+7
+7
+4
+2
+7
+9
+1
+2
+1
+4
+6
+2
+6
+6
+0
+7
+6
+1
+8
+3
+8
+8
+4
+8
+8
+5
+9
+7
+8
+2
+1
+4
+4
+0
+2
+6
+3
+6
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+7
+9
+9
+2
+8
+3
+7
+5
+0
+1
+5
+7
+7
+2
+8
+8
+8
+9
+0
+8
+5
+8
+2
+8
+1
+7
+9
+5
+0
+3
+0
+6
+6
+7
+3
+3
+1
+5
+0
+2
+9
+2
+3
+1
+2
+7
+1
+9
+0
+7
+1
+4
+1
+2
+2
+7
+0
+1
+6
+3
+0
+6
+5
+6
+6
+1
+3
+7
+4
+3
+4
+4
+9
+0
+1
+6
+6
+9
+7
+5
+2
+6
+0
+7
+7
+2
+2
+5
+9
+6
+4
+4
+5
+3
+7
+9
+1
+0
+4
+1
+3
+9
+1
+2
+9
+7
+7
+0
+3
+0
+4
+7
+5
+1
+5
+0
+5
+9
+2
+4
+9
+5
+2
+5
+3
+6
+6
+0
+7
+4
+1
+5
+3
+9
+9
+3
+0
+7
+6
+7
+7
+2
+3
+6
+6
+2
+0
+5
+3
+6
+6
+6
+4
+7
+4
+4
+5
+9
+9
+3
+9
+9
+4
+9
+1
+8
+8
+8
+8
+8
+8
+8
+8
+8
+1
+6
+7
+2
+1
+7
+3
+6
+6
+1
+3
+9
+6
+6
+4
+7
+4
+4
+7
+6
+6
+5
+8
+8
+5
+1
+6
+7
+9
+2
+7
+5
+3
+5
+4
+8
+8
+8
+0
+1
+0
+5
+8
+2
+5
+8
+8
+8
+3
+7
+0
+3
+9
+0
+5
+0
+7
+2
+7
+3
+9
+7
+2
+1
+6
+0
+5
+1
+9
+4
+2
+4
+3
+0
+8
+3
+9
+7
+4
+1
+2
+4
+6
+3
+1
+5
+4
+6
+5
+9
+6
+4
+9
+3
+0
+0
+0
+9
+4
+0
+9
+6
+6
+7
+0
+9
+3
+3
+4
+0
+5
+4
+2
+9
+3
+3
+0
+8
+1
+1
+2
+1
+3
+6
+4
+1
+7
+4
+1
+2
+3
+0
+6
+4
+6
+9
+9
+6
+5
+1
+2
+1
+7
+2
+9
+4
+3
+5
+2
+9
+0
+7
+0
+1
+7
+4
+1
+9
+1
+5
+9
+2
+4
+3
+7
+5
+4
+1
+4
+4
+2
+4
+0
+3
+5
+2
+6
+5
+6
+4
+2
+1
+5
+5
+1
+0
+4
+6
+4
+5
+6
+3
+0
+2
+5
+1
+3
+9
+2
+6
+6
+6
+5
+2
+3
+9
+1
+0
+4
+4
+0
+0
+2
+6
+7
+3
+5
+6
+5
+1
+3
+2
+3
+5
+7
+5
+0
+7
+3
+0
+4
+0
+9
+5
+1
+2
+5
+9
+9
+3
+2
+0
+7
+2
+6
+3
+6
+3
+2
+7
+6
+9
+2
+1
+6
+3
+1
+9
+0
+4
+3
+0
+1
+7
+6
+9
+4
+1
+4
+4
+2
+3
+1
+0
+1
+2
+8
+8
+8
+4
+8
+1
+9
+8
+0
+8
+5
+6
+4
+4
+9
+7
+7
+2
+7
+8
+8
+8
+8
+8
+8
+8
+3
+8
+8
+8
+9
+0
+2
+1
+5
+9
+2
+6
+6
+8
+4
+5
+8
+7
+5
+3
+7
+1
+8
+2
+0
+8
+0
+3
+5
+8
+8
+8
+2
+2
+7
+5
+9
+5
+4
+4
+1
+4
+2
+3
+0
+3
+7
+2
+7
+5
+3
+0
+9
+8
+1
+2
+4
+9
+3
+0
+1
+6
+6
+8
+5
+9
+3
+7
+7
+6
+6
+6
+6
+1
+4
+9
+0
+2
+0
+5
+0
+7
+2
+5
+9
+5
+2
+7
+4
+1
+5
+9
+9
+3
+9
+1
+5
+7
+7
+2
+9
+4
+4
+3
+2
+9
+0
+1
+4
+2
+1
+0
+1
+9
+2
+6
+6
+1
+2
+3
+5
+6
+6
+1
+9
+7
+7
+3
+4
+6
+5
+2
+9
+6
+6
+0
+2
+0
+1
+6
+5
+2
+0
+7
+7
+1
+9
+5
+4
+1
+2
+1
+6
+9
+5
+0
+9
+7
+3
+2
+1
+9
+0
+5
+2
+2
+1
+4
+2
+8
+8
+8
+8
+8
+8
+8
+8
+8
+6
+8
+8
+7
+4
+4
+5
+4
+9
+2
+1
+6
+6
+5
+3
+3
+5
+4
+0
+8
+4
+5
+8
+4
+8
+8
+8
+9
+8
+8
+3
+2
+0
+5
+8
+9
+3
+3
+1
+8
+8
+8
+8
+6
+7
+8
+8
+8
+8
+8
+8
+1
+9
+2
+3
+5
+7
+1
+2
+6
+1
+6
+6
+2
+8
+3
+8
+6
+5
+8
+6
+8
+2
+1
+0
+9
+9
+7
+3
+8
+5
+2
+8
+7
+7
+1
+2
+2
+1
+0
+2
+0
+9
+8
+0
+2
+3
+9
+4
+1
+9
+1
+4
+7
+2
+4
+7
+4
+9
+0
+1
+0
+3
+2
+4
+7
+1
+7
+7
+5
+0
+9
+2
+6
+4
+4
+6
+4
+7
+9
+0
+7
+5
+0
+5
+6
+3
+9
+1
+3
+0
+5
+4
+7
+5
+9
+5
+7
+4
+5
+0
+1
+5
+2
+7
+3
+6
+5
+4
+6
+4
+6
+0
+2
+7
+5
+1
+7
+9
+5
+6
+4
+2
+1
+5
+9
+9
+3
+4
+6
+6
+9
+6
+5
+9
+2
+0
+0
+1
+9
+2
+2
+7
+7
+5
+3
+0
+6
+7
+9
+9
+7
+4
+5
+4
+9
+0
+0
+0
+2
+5
+0
+4
+7
+9
+4
+1
+4
+5
+5
+7
+0
+9
+6
+7
+4
+7
+1
+2
+9
+7
+0
+2
+4
+3
+6
+2
+6
+1
+7
+7
+0
+4
+4
+1
+2
+9
+5
+6
+6
+6
+1
+7
+4
+2
+3
+1
+7
+5
+4
+5
+3
+9
+4
+2
+0
+1
+5
+3
+3
+9
+0
+5
+1
+7
+9
+3
+7
+7
+8
+8
+8
+8
+8
+8
+8
+8
+5
+8
+8
+9
+7
+4
+3
+2
+4
+5
+0
+3
+9
+5
+3
+4
+7
+2
+4
+3
+8
+0
+8
+5
+3
+4
+4
+9
+4
+1
+2
+0
+3
+0
+7
+7
+8
+8
+8
+2
+8
+0
+8
+9
+5
+8
+8
+8
+3
+2
+6
+9
+8
+4
+1
+3
+9
+1
+2
+9
+7
+6
+6
+6
+1
+4
+0
+2
+1
+6
+4
+8
+2
+1
+5
+9
+7
+7
+8
+3
+9
+2
+7
+9
+6
+1
+6
+5
+5
+4
+4
+7
+0
+5
+7
+2
+9
+3
+3
+2
+0
+5
+8
+3
+2
+7
+3
+1
+5
+4
+0
+7
+0
+6
+3
+0
+7
+2
+6
+3
+0
+9
+6
+4
+0
+0
+4
+3
+7
+5
+0
+1
+7
+7
+5
+1
+3
+9
+0
+5
+2
+3
+9
+4
+3
+6
+4
+1
+5
+0
+9
+9
+3
+4
+1
+5
+4
+1
+2
+5
+7
+3
+6
+7
+0
+3
+7
+9
+5
+6
+1
+6
+2
+1
+6
+9
+7
+7
+3
+1
+9
+5
+1
+0
+8
+8
+8
+8
+3
+8
+8
+8
+8
+8
+8
+0
+1
+4
+5
+2
+4
+3
+3
+0
+2
+0
+9
+1
+1
+3
+4
+4
+5
+1
+8
+4
+8
+4
+4
+3
+4
+9
+2
+7
+6
+6
+8
+4
+3
+8
+8
+2
+5
+8
+8
+1
+7
+8
+6
+6
+8
+2
+1
+8
+3
+5
+8
+8
+1
+2
+0
+9
+5
+7
+4
+8
+9
+5
+7
+1
+8
+8
+2
+1
+8
+5
+8
+9
+3
+6
+1
+8
+2
+1
+7
+7
+0
+2
+1
+0
+6
+2
+1
+3
+6
+1
+6
+7
+9
+8
+2
+3
+6
+6
+6
+6
+0
+4
+4
+3
+4
+7
+7
+7
+2
+2
+0
+1
+4
+5
+1
+5
+7
+7
+7
+0
+5
+3
+4
+0
+4
+9
+2
+2
+1
+0
+3
+2
+9
+5
+7
+2
+2
+2
+7
+1
+2
+9
+6
+6
+5
+2
+3
+1
+3
+9
+7
+9
+6
+6
+9
+6
+3
+9
+2
+4
+7
+6
+3
+4
+7
+0
+6
+2
+2
+3
+3
+6
+9
+9
+1
+5
+2
+9
+3
+9
+1
+7
+1
+7
+6
+9
+7
+9
+0
+5
+6
+1
+4
+5
+3
+0
+6
+5
+6
+6
+9
+4
+4
+7
+5
+1
+0
+1
+2
+9
+0
+6
+0
+2
+1
+7
+9
+2
+6
+4
+3
+4
+0
+4
+9
+9
+2
+5
+3
+4
+0
+7
+0
+9
+3
+2
+3
+0
+1
+5
+2
+0
+1
+3
+3
+1
+3
+1
+5
+4
+4
+0
+1
+0
+3
+6
+4
+7
+2
+3
+3
+6
+9
+2
+6
+9
+6
+1
+5
+4
+9
+0
+8
+6
+7
+0
+4
+0
+5
+9
+1
+8
+8
+8
+7
+7
+8
+9
+6
+1
+2
+5
+8
+8
+8
+8
+8
+8
+8
+2
+8
+3
+8
+9
+7
+7
+9
+0
+6
+4
+3
+6
+4
+8
+9
+8
+8
+3
+3
+4
+5
+8
+8
+8
+8
+8
+3
+7
+8
+0
+2
+8
+5
+1
+3
+8
+1
+4
+7
+7
+2
+3
+1
+8
+3
+1
+9
+9
+7
+2
+4
+7
+7
+8
+4
+5
+5
+3
+2
+8
+8
+6
+5
+2
+0
+3
+6
+2
+3
+5
+1
+4
+2
+4
+4
+5
+5
+2
+6
+6
+1
+5
+7
+7
+1
+6
+0
+9
+0
+5
+2
+4
+3
+4
+4
+1
+7
+3
+7
+2
+9
+1
+3
+6
+4
+2
+5
+0
+7
+5
+3
+7
+5
+4
+4
+3
+3
+0
+2
+5
+5
+4
+2
+1
+9
+7
+5
+0
+6
+0
+7
+2
+3
+7
+6
+2
+5
+0
+9
+3
+2
+9
+6
+5
+7
+2
+9
+3
+3
+2
+2
+1
+7
+3
+7
+7
+5
+0
+2
+2
+6
+6
+3
+2
+7
+9
+3
+2
+8
+5
+8
+8
+8
+6
+8
+8
+8
+8
+8
+9
+7
+7
+4
+7
+1
+6
+5
+6
+3
+1
+2
+0
+0
+0
+4
+1
+6
+3
+1
+2
+5
+1
+4
+9
+4
+3
+0
+8
+7
+2
+7
+5
+1
+8
+8
+8
+8
+8
+8
+9
+5
+3
+2
+1
+7
+7
+0
+9
+2
+1
+5
+1
+9
+2
+8
+0
+1
+7
+1
+7
+6
+2
+5
+9
+5
+4
+4
+8
+3
+6
+0
+1
+6
+7
+2
+5
+9
+0
+7
+2
+8
+3
+7
+9
+3
+4
+1
+2
+2
+0
+9
+9
+2
+7
+7
+5
+8
+3
+9
+7
+1
+2
+4
+8
+4
+3
+1
+9
+7
+7
+2
+4
+4
+0
+5
+3
+6
+5
+1
+2
+9
+1
+4
+0
+5
+2
+7
+0
+6
+2
+6
+9
+1
+0
+5
+6
+7
+5
+2
+9
+3
+4
+2
+1
+9
+1
+1
+5
+0
+1
+3
+2
+2
+5
+7
+7
+1
+2
+0
+5
+1
+2
+1
+4
+3
+1
+4
+1
+9
+7
+2
+1
+6
+6
+3
+6
+4
+9
+5
+2
+7
+7
+0
+4
+3
+9
+6
+6
+6
+0
+5
+6
+6
+9
+4
+0
+4
+3
+5
+1
+9
+9
+0
+4
+0
+3
+2
+0
+0
+4
+2
+5
+9
+3
+3
+9
+6
+6
+5
+2
+9
+4
+4
+1
+0
+5
+0
+1
+9
+2
+6
+5
+7
+2
+0
+7
+0
+1
+7
+4
+5
+6
+6
+6
+7
+9
+1
+2
+3
+1
+7
+2
+5
+9
+0
+0
+4
+2
+6
+3
+9
+3
+5
+0
+3
+5
+7
+7
+9
+9
+2
+1
+8
+4
+1
+8
+4
+1
+8
+7
+8
+8
+5
+2
+1
+8
+8
+6
+1
+0
+1
+4
+6
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+0
+7
+2
+7
+6
+5
+6
+2
+1
+3
+0
+8
+0
+7
+5
+0
+8
+7
+3
+8
+0
+2
+7
+1
+8
+5
+9
+8
+8
+8
+0
+8
+0
+9
+3
+5
+7
+6
+6
+6
+9
+9
+0
+4
+2
+5
+4
+2
+9
+4
+4
+1
+0
+7
+8
+5
+9
+9
+1
+8
+8
+2
+5
+3
+5
+7
+3
+4
+8
+4
+1
+0
+0
+1
+3
+5
+5
+7
+9
+2
+4
+9
+3
+7
+2
+2
+7
+7
+9
+3
+4
+0
+4
+0
+9
+1
+0
+0
+1
+7
+3
+6
+2
+9
+6
+6
+6
+6
+1
+5
+4
+2
+1
+6
+1
+6
+2
+0
+9
+5
+5
+2
+3
+1
+3
+7
+5
+0
+5
+1
+0
+3
+0
+5
+2
+9
+1
+7
+1
+2
+5
+1
+3
+7
+4
+1
+3
+3
+3
+2
+0
+9
+0
+4
+4
+3
+4
+6
+1
+6
+0
+3
+6
+6
+8
+8
+8
+8
+8
+5
+8
+8
+8
+1
+8
+8
+2
+4
+4
+5
+3
+9
+5
+7
+2
+3
+7
+4
+6
+4
+4
+5
+8
+7
+9
+3
+0
+4
+1
+8
+6
+1
+2
+3
+8
+8
+3
+4
+8
+8
+8
+3
+7
+5
+6
+6
+0
+8
+8
+3
+5
+2
+8
+1
+7
+0
+1
+6
+4
+3
+5
+1
+8
+8
+9
+9
+1
+0
+3
+2
+1
+4
+4
+5
+4
+0
+3
+8
+8
+2
+9
+1
+1
+2
+3
+5
+3
+1
+0
+0
+0
+4
+4
+2
+4
+7
+5
+9
+7
+6
+0
+6
+4
+1
+7
+9
+2
+6
+0
+0
+6
+0
+6
+9
+4
+2
+1
+7
+7
+7
+0
+7
+1
+3
+9
+4
+9
+5
+4
+5
+4
+1
+2
+1
+7
+7
+4
+5
+4
+3
+7
+0
+6
+0
+6
+6
+2
+5
+9
+5
+3
+2
+7
+4
+6
+6
+1
+5
+0
+1
+6
+1
+7
+7
+2
+3
+5
+6
+6
+4
+1
+5
+4
+9
+3
+1
+0
+1
+5
+7
+9
+1
+4
+2
+3
+0
+9
+1
+5
+4
+7
+4
+4
+5
+9
+4
+2
+0
+1
+4
+0
+5
+4
+1
+9
+3
+2
+6
+5
+1
+6
+4
+6
+7
+3
+2
+3
+4
+9
+4
+4
+0
+5
+0
+6
+7
+9
+9
+6
+4
+6
+0
+3
+6
+9
+5
+6
+1
+2
+3
+3
+0
+5
+0
+1
+9
+2
+2
+3
+9
+5
+2
+5
+0
+6
+3
+3
+6
+4
+6
+7
+7
+4
+6
+3
+9
+6
+6
+6
+4
+2
+7
+3
+0
+7
+0
+7
+7
+8
+4
+6
+8
+3
+2
+1
+5
+7
+1
+0
+4
+3
+8
+5
+8
+9
+3
+2
+9
+1
+8
+8
+8
+8
+8
+8
+5
+8
+6
+7
+1
+9
+9
+0
+3
+7
+2
+5
+0
+9
+9
+7
+3
+1
+6
+6
+6
+1
+8
+2
+8
+6
+6
+0
+2
+0
+9
+5
+7
+2
+5
+8
+8
+6
+6
+4
+3
+6
+2
+3
+5
+1
+9
+0
+0
+0
+0
+9
+4
+5
+9
+2
+3
+7
+4
+4
+1
+4
+9
+8
+3
+2
+2
+3
+4
+2
+0
+8
+4
+2
+9
+6
+6
+4
+2
+7
+7
+9
+0
+3
+5
+4
+5
+6
+3
+9
+0
+2
+4
+7
+4
+1
+3
+4
+5
+0
+2
+2
+4
+5
+3
+7
+3
+1
+7
+5
+1
+5
+4
+9
+3
+5
+9
+5
+7
+2
+3
+1
+7
+3
+7
+6
+6
+8
+5
+5
+9
+3
+1
+3
+7
+9
+7
+5
+6
+0
+1
+0
+2
+9
+6
+1
+0
+1
+6
+1
+5
+6
+6
+9
+3
+2
+7
+2
+4
+9
+1
+4
+5
+3
+0
+2
+1
+7
+9
+4
+0
+6
+3
+1
+2
+9
+9
+7
+4
+5
+0
+7
+1
+9
+7
+9
+5
+2
+3
+3
+0
+9
+5
+6
+6
+1
+6
+5
+1
+2
+0
+6
+3
+2
+6
+1
+5
+6
+2
+2
+3
+9
+7
+2
+9
+4
+5
+5
+2
+3
+1
+1
+2
+8
+3
+7
+7
+1
+5
+3
+5
+2
+4
+1
+3
+4
+0
+3
+7
+7
+2
+2
+5
+9
+9
+2
+0
+5
+1
+1
+5
+9
+4
+7
+2
+1
+0
+5
+0
+7
+6
+0
+4
+2
+0
+4
+6
+5
+3
+6
+6
+7
+2
+0
+4
+4
+9
+2
+6
+0
+6
+0
+2
+1
+9
+3
+1
+7
+7
+1
+3
+0
+3
+6
+5
+1
+6
+7
+1
+7
+7
+5
+0
+3
+0
+1
+5
+1
+9
+4
+2
+5
+7
+9
+7
+0
+4
+0
+4
+4
+0
+9
+6
+5
+9
+4
+1
+6
+9
+7
+7
+5
+4
+1
+5
+2
+7
+2
+1
+4
+2
+3
+4
+9
+2
+2
+9
+0
+1
+0
+2
+5
+9
+0
+5
+1
+3
+0
+3
+3
+9
+7
+4
+2
+5
+9
+3
+3
+0
+6
+0
+6
+2
+5
+7
+3
+1
+6
+7
+7
+6
+6
+3
+7
+9
+5
+2
+5
+0
+6
+8
+8
+8
+8
+8
+7
+8
+8
+5
+8
+8
+8
+8
+0
+2
+9
+8
+4
+5
+3
+8
+8
+8
+8
+8
+8
+4
+3
+8
+8
+8
+9
+9
+7
+7
+8
+1
+0
+1
+0
+9
+8
+3
+6
+6
+3
+2
+7
+7
+8
+3
+8
+5
+8
+8
+6
+9
+6
+3
+5
+8
+8
+8
+4
+1
+8
+3
+5
+8
+0
+7
+1
+4
+4
+3
+4
+0
+2
+9
+0
+1
+8
+2
+9
+0
+7
+2
+6
+6
+0
+4
+0
+5
+1
+6
+7
+2
+7
+0
+6
+9
+3
+5
+5
+1
+6
+6
+9
+9
+5
+0
+5
+7
+6
+1
+9
+4
+4
+0
+4
+0
+1
+5
+5
+9
+3
+1
+4
+6
+7
+6
+9
+3
+5
+4
+0
+4
+4
+1
+4
+3
+7
+7
+0
+0
+7
+7
+2
+3
+1
+9
+2
+1
+5
+0
+6
+0
+4
+6
+0
+5
+9
+4
+9
+1
+2
+5
+6
+7
+2
+6
+1
+9
+7
+3
+3
+6
+9
+2
+0
+1
+6
+6
+3
+7
+9
+7
+5
+2
+0
+7
+3
+1
+7
+1
+5
+2
+5
+4
+1
+6
+0
+5
+0
+7
+6
+5
+7
+9
+2
+7
+0
+3
+6
+1
+1
+9
+4
+2
+2
+5
+1
+5
+6
+4
+5
+6
+4
+2
+9
+3
+7
+0
+2
+4
+1
+4
+4
+1
+5
+9
+2
+1
+1
+4
+4
+2
+4
+9
+1
+5
+7
+1
+9
+3
+1
+8
+3
+0
+8
+8
+8
+9
+7
+3
+8
+0
+8
+8
+8
+6
+1
+5
+3
+0
+0
+6
+9
+2
+7
+7
+3
+6
+2
+5
+9
+0
+8
+4
+4
+8
+3
+1
+6
+6
+8
+3
+8
+8
+1
+8
+5
+9
+8
+3
+8
+8
+8
+8
+8
+2
+4
+3
+7
+7
+8
+8
+8
+4
+5
+1
+3
+4
+6
+4
+6
+6
+1
+2
+3
+6
+5
+7
+2
+7
+7
+7
+6
+0
+9
+0
+5
+1
+1
+5
+3
+2
+4
+9
+1
+3
+2
+3
+9
+5
+0
+2
+1
+0
+7
+3
+5
+4
+3
+4
+0
+7
+3
+3
+7
+1
+1
+9
+0
+5
+6
+6
+9
+2
+7
+7
+6
+6
+1
+0
+9
+3
+3
+6
+2
+5
+7
+7
+6
+9
+5
+0
+2
+6
+4
+6
+6
+6
+3
+0
+5
+4
+7
+4
+4
+2
+2
+9
+7
+0
+6
+4
+1
+0
+4
+0
+3
+1
+1
+5
+5
+4
+1
+4
+4
+5
+2
+5
+2
+9
+3
+1
+4
+0
+5
+0
+7
+1
+6
+6
+3
+6
+5
+1
+6
+0
+2
+4
+9
+6
+1
+7
+1
+5
+5
+2
+3
+4
+4
+9
+2
+3
+5
+5
+9
+1
+1
+0
+2
+3
+4
+6
+1
+7
+8
+8
+8
+8
+2
+3
+8
+9
+0
+6
+5
+7
+8
+5
+6
+9
+0
+8
+4
+1
+8
+8
+8
+8
+8
+8
+8
+4
+8
+8
+4
+9
+3
+6
+8
+6
+9
+4
+4
+7
+4
+2
+8
+1
+9
+3
+8
+4
+8
+8
+0
+8
+0
+7
+2
+9
+8
+5
+7
+2
+9
+3
+0
+2
+2
+7
+1
+5
+9
+1
+7
+0
+0
+0
+5
+4
+1
+5
+1
+3
+3
+0
+4
+8
+9
+1
+2
+7
+3
+6
+6
+6
+9
+0
+6
+3
+3
+1
+9
+2
+7
+7
+0
+0
+9
+0
+1
+5
+5
+6
+5
+3
+3
+2
+9
+9
+5
+4
+4
+1
+4
+6
+7
+7
+0
+0
+2
+5
+9
+5
+9
+2
+6
+6
+7
+7
+2
+4
+3
+6
+4
+5
+6
+1
+9
+2
+5
+1
+7
+3
+7
+3
+9
+0
+1
+4
+2
+1
+5
+3
+7
+9
+0
+2
+0
+5
+4
+0
+9
+9
+3
+5
+5
+2
+5
+4
+9
+7
+3
+4
+5
+1
+0
+3
+0
+9
+2
+0
+6
+6
+6
+6
+4
+0
+7
+5
+3
+1
+9
+4
+6
+6
+6
+6
+1
+2
+9
+7
+6
+6
+7
+7
+4
+0
+6
+5
+5
+9
+2
+4
+3
+4
+5
+0
+7
+7
+2
+7
+3
+9
+5
+2
+6
+6
+1
+4
+3
+4
+4
+6
+7
+3
+3
+0
+9
+2
+6
+1
+4
+3
+3
+6
+9
+7
+1
+5
+6
+8
+6
+3
+8
+8
+8
+8
+5
+8
+8
+8
+2
+7
+8
+8
+7
+2
+5
+1
+3
+2
+0
+0
+0
+0
+1
+4
+3
+1
+2
+1
+1
+4
+4
+8
+4
+8
+3
+2
+0
+7
+9
+5
+6
+6
+7
+6
+8
+8
+9
+8
+6
+6
+8
+8
+4
+8
+9
+8
+7
+8
+3
+5
+4
+6
+1
+9
+6
+1
+6
+6
+7
+4
+4
+9
+1
+5
+1
+0
+8
+2
+0
+8
+0
+3
+3
+5
+7
+7
+9
+7
+1
+3
+2
+8
+9
+6
+2
+3
+6
+6
+7
+5
+1
+9
+1
+2
+2
+4
+5
+1
+2
+1
+6
+3
+3
+2
+7
+1
+9
+3
+0
+5
+0
+1
+1
+0
+9
+9
+2
+7
+1
+0
+5
+2
+9
+5
+4
+2
+2
+7
+0
+0
+2
+7
+7
+1
+1
+3
+3
+4
+6
+4
+4
+3
+4
+5
+6
+6
+3
+4
+2
+2
+6
+6
+9
+5
+3
+9
+6
+4
+2
+4
+5
+3
+3
+0
+6
+6
+6
+2
+9
+6
+3
+1
+0
+0
+7
+7
+9
+4
+0
+8
+1
+2
+8
+8
+8
+8
+8
+7
+3
+8
+0
+8
+8
+9
+1
+2
+0
+5
+0
+2
+9
+3
+7
+7
+5
+1
+6
+5
+6
+6
+0
+1
+9
+8
+8
+8
+8
+3
+1
+8
+0
+8
+7
+8
+5
+2
+3
+8
+0
+7
+8
+8
+8
+8
+8
+8
+8
+8
+6
+8
+4
+3
+8
+8
+3
+4
+5
+4
+2
+0
+6
+6
+3
+2
+6
+6
+7
+2
+8
+5
+9
+1
+2
+6
+6
+6
+8
+2
+3
+0
+4
+1
+7
+7
+6
+0
+2
+6
+4
+7
+2
+5
+5
+3
+7
+7
+3
+4
+5
+0
+5
+4
+4
+9
+0
+0
+1
+8
+7
+2
+9
+9
+5
+9
+0
+0
+9
+3
+1
+4
+5
+4
+4
+7
+9
+5
+9
+3
+1
+6
+0
+6
+2
+5
+1
+9
+3
+6
+0
+4
+9
+2
+7
+1
+4
+5
+2
+5
+4
+2
+5
+1
+0
+5
+9
+9
+7
+4
+4
+7
+4
+6
+0
+9
+5
+3
+3
+2
+2
+5
+5
+1
+2
+7
+3
+6
+3
+4
+1
+9
+0
+0
+2
+3
+9
+7
+2
+6
+4
+5
+2
+3
+9
+0
+3
+5
+0
+5
+6
+4
+2
+7
+9
+9
+2
+2
+0
+7
+3
+1
+9
+9
+4
+7
+5
+0
+9
+3
+7
+7
+5
+0
+4
+1
+9
+3
+5
+0
+5
+4
+4
+2
+7
+5
+3
+0
+0
+6
+2
+5
+9
+4
+6
+6
+3
+0
+1
+7
+5
+1
+0
+1
+3
+6
+6
+6
+1
+9
+1
+5
+6
+0
+1
+7
+2
+9
+6
+6
+5
+2
+0
+1
+0
+2
+3
+5
+9
+8
+5
+9
+7
+2
+8
+8
+8
+8
+8
+6
+5
+8
+8
+8
+9
+6
+9
+9
+7
+3
+6
+1
+9
+5
+0
+9
+2
+3
+1
+0
+0
+9
+6
+5
+4
+8
+8
+8
+3
+9
+8
+8
+8
+8
+2
+3
+3
+8
+8
+8
+0
+8
+7
+2
+3
+8
+1
+8
+2
+1
+0
+4
+1
+2
+7
+8
+8
+5
+0
+0
+0
+0
+3
+1
+4
+7
+9
+6
+7
+9
+7
+7
+6
+6
+5
+2
+2
+9
+6
+0
+7
+0
+4
+3
+6
+3
+1
+5
+5
+1
+9
+6
+7
+3
+2
+7
+1
+8
+7
+7
+9
+5
+3
+0
+0
+0
+9
+3
+4
+9
+3
+1
+7
+2
+9
+4
+3
+6
+7
+5
+9
+2
+6
+0
+1
+4
+3
+6
+9
+5
+2
+3
+4
+0
+5
+6
+9
+7
+9
+3
+3
+4
+7
+2
+4
+0
+1
+3
+0
+3
+3
+7
+4
+9
+7
+9
+4
+3
+0
+5
+0
+6
+4
+1
+7
+7
+2
+1
+5
+4
+7
+7
+6
+6
+3
+6
+2
+1
+0
+4
+1
+8
+0
+7
+8
+2
+8
+6
+8
+1
+8
+8
+8
+8
+8
+8
+4
+7
+5
+6
+9
+9
+0
+4
+0
+1
+3
+0
+3
+9
+5
+9
+5
+4
+1
+3
+4
+1
+8
+8
+8
+8
+9
+4
+1
+0
+2
+7
+1
+8
+9
+8
+5
+8
+8
+2
+8
+8
+9
+1
+2
+7
+6
+6
+7
+0
+6
+7
+3
+4
+4
+8
+5
+9
+5
+3
+3
+0
+8
+4
+8
+9
+5
+0
+3
+5
+2
+1
+9
+9
+8
+8
+6
+6
+1
+6
+2
+9
+7
+3
+1
+2
+9
+0
+6
+2
+8
+5
+7
+4
+9
+1
+9
+4
+4
+7
+5
+6
+6
+0
+0
+9
+1
+3
+7
+7
+9
+2
+2
+5
+6
+4
+6
+4
+0
+6
+4
+2
+5
+1
+1
+3
+7
+9
+0
+9
+5
+3
+3
+5
+2
+4
+7
+4
+0
+2
+0
+3
+9
+7
+2
+4
+1
+0
+4
+1
+9
+9
+3
+9
+7
+7
+1
+4
+4
+3
+1
+9
+0
+4
+6
+6
+9
+9
+3
+0
+6
+1
+2
+3
+9
+5
+3
+1
+9
+2
+2
+0
+4
+0
+3
+7
+9
+7
+6
+6
+7
+7
+4
+1
+9
+4
+9
+3
+4
+1
+6
+0
+6
+6
+7
+3
+1
+7
+4
+0
+9
+2
+2
+6
+6
+4
+7
+2
+4
+9
+5
+2
+4
+3
+3
+0
+6
+5
+4
+3
+2
+6
+3
+7
+2
+9
+0
+0
+4
+3
+9
+5
+3
+9
+2
+7
+4
+7
+9
+2
+0
+1
+0
+2
+2
+4
+3
+5
+5
+9
+0
+5
+1
+3
+3
+6
+3
+7
+5
+6
+6
+2
+8
+8
+1
+8
+2
+6
+5
+7
+8
+8
+6
+8
+3
+8
+8
+8
+1
+8
+4
+5
+8
+8
+8
+8
+0
+8
+8
+1
+8
+4
+4
+8
+8
+3
+4
+8
+4
+7
+8
+5
+1
+3
+7
+4
+9
+8
+6
+9
+5
+6
+3
+8
+8
+8
+0
+1
+4
+8
+8
+7
+5
+8
+1
+4
+6
+0
+6
+6
+7
+8
+5
+2
+2
+5
+4
+0
+9
+2
+8
+1
+8
+2
+8
+1
+9
+7
+8
+9
+8
+3
+5
+8
+3
+6
+2
+0
+7
+7
+0
+3
+0
+9
+4
+5
+2
+6
+5
+3
+6
+9
+6
+6
+7
+2
+5
+4
+6
+4
+7
+6
+4
+1
+2
+3
+5
+9
+2
+4
+6
+6
+1
+2
+2
+1
+0
+4
+2
+5
+9
+0
+1
+3
+3
+7
+1
+2
+1
+5
+5
+9
+3
+1
+1
+5
+5
+1
+0
+9
+3
+5
+5
+0
+5
+1
+9
+6
+2
+9
+1
+6
+6
+6
+5
+1
+5
+2
+6
+4
+4
+6
+9
+0
+7
+9
+3
+5
+1
+4
+9
+4
+1
+0
+3
+6
+7
+5
+1
+9
+2
+3
+4
+1
+5
+2
+7
+7
+0
+2
+7
+5
+7
+1
+2
+9
+0
+5
+0
+2
+1
+0
+6
+9
+7
+6
+8
+8
+8
+8
+8
+8
+2
+8
+6
+3
+9
+1
+5
+0
+7
+2
+0
+8
+3
+0
+2
+8
+8
+8
+8
+8
+0
+8
+7
+8
+8
+8
+6
+3
+6
+5
+3
+4
+2
+1
+4
+3
+5
+7
+3
+8
+1
+0
+2
+3
+9
+8
+8
+1
+8
+0
+5
+7
+9
+8
+3
+8
+8
+8
+6
+1
+3
+0
+0
+0
+6
+4
+1
+4
+4
+5
+3
+1
+7
+0
+9
+3
+7
+2
+5
+8
+5
+0
+2
+3
+3
+4
+7
+7
+4
+7
+9
+9
+3
+5
+1
+4
+9
+8
+7
+7
+5
+3
+6
+5
+9
+1
+0
+9
+3
+1
+3
+0
+4
+5
+2
+7
+6
+6
+3
+1
+5
+1
+0
+9
+5
+3
+6
+7
+6
+9
+6
+9
+0
+1
+5
+4
+3
+9
+6
+4
+0
+2
+0
+7
+1
+0
+2
+1
+7
+7
+3
+4
+0
+9
+7
+7
+6
+5
+5
+3
+7
+7
+4
+0
+2
+2
+9
+5
+1
+2
+2
+0
+1
+2
+7
+7
+3
+5
+5
+6
+4
+0
+1
+3
+6
+9
+5
+1
+9
+1
+7
+2
+3
+0
+1
+0
+7
+9
+5
+3
+2
+1
+4
+0
+2
+3
+5
+9
+3
+2
+7
+5
+9
+0
+2
+0
+6
+5
+0
+5
+4
+9
+4
+2
+1
+7
+3
+6
+5
+4
+0
+5
+2
+1
+7
+6
+5
+1
+7
+0
+6
+2
+4
+1
+7
+9
+2
+1
+5
+4
+9
+8
+0
+6
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+0
+8
+3
+7
+9
+9
+5
+3
+1
+7
+9
+1
+9
+9
+2
+6
+4
+7
+9
+9
+3
+7
+8
+8
+8
+1
+9
+6
+3
+0
+6
+5
+2
+6
+0
+8
+8
+8
+6
+4
+8
+6
+4
+8
+8
+8
+1
+8
+5
+4
+2
+1
+8
+4
+9
+4
+5
+7
+1
+2
+3
+0
+9
+0
+8
+6
+8
+1
+8
+8
+7
+6
+2
+3
+1
+4
+6
+6
+4
+8
+8
+5
+7
+6
+3
+0
+1
+0
+6
+6
+5
+2
+3
+4
+9
+9
+4
+1
+7
+7
+3
+1
+9
+5
+0
+0
+0
+0
+1
+2
+9
+1
+5
+1
+2
+3
+1
+6
+3
+9
+0
+4
+0
+3
+4
+1
+7
+9
+7
+7
+4
+3
+7
+7
+5
+9
+1
+4
+6
+4
+4
+2
+4
+9
+6
+5
+8
+5
+9
+3
+6
+6
+2
+1
+7
+7
+9
+4
+3
+4
+7
+0
+6
+6
+6
+6
+0
+1
+4
+5
+4
+7
+7
+3
+1
+9
+0
+7
+2
+1
+9
+9
+7
+6
+0
+7
+0
+2
+6
+6
+3
+0
+5
+4
+5
+3
+6
+6
+7
+7
+2
+1
+1
+3
+0
+5
+0
+1
+1
+2
+8
+7
+8
+3
+1
+8
+8
+8
+8
+2
+8
+3
+8
+8
+8
+1
+9
+8
+4
+1
+4
+8
+8
+8
+8
+8
+8
+3
+8
+5
+8
+2
+1
+9
+7
+4
+8
+4
+4
+0
+4
+2
+8
+6
+7
+3
+5
+7
+7
+9
+8
+7
+8
+8
+3
+6
+9
+9
+4
+0
+4
+0
+3
+2
+2
+9
+6
+6
+4
+3
+9
+1
+3
+2
+0
+4
+0
+4
+9
+0
+9
+9
+1
+5
+0
+3
+2
+2
+9
+9
+5
+2
+7
+6
+0
+7
+6
+1
+5
+6
+9
+9
+6
+5
+1
+2
+0
+3
+0
+9
+5
+4
+7
+2
+0
+4
+0
+5
+4
+9
+1
+0
+2
+5
+9
+9
+1
+2
+3
+4
+4
+2
+5
+9
+1
+4
+3
+4
+4
+5
+6
+2
+7
+7
+0
+5
+7
+1
+4
+6
+0
+9
+3
+6
+1
+6
+7
+7
+4
+7
+1
+0
+9
+2
+2
+4
+6
+6
+7
+7
+9
+0
+0
+0
+5
+4
+5
+6
+9
+0
+0
+0
+1
+3
+7
+1
+9
+5
+5
+9
+7
+3
+2
+1
+3
+9
+5
+7
+5
+1
+1
+3
+7
+9
+5
+2
+0
+3
+3
+5
+3
+5
+4
+1
+2
+3
+6
+6
+2
+9
+1
+4
+4
+2
+9
+1
+3
+1
+4
+5
+9
+2
+1
+7
+3
+4
+2
+1
+7
+3
+5
+9
+5
+4
+1
+2
+5
+3
+4
+9
+2
+5
+6
+6
+1
+7
+4
+8
+3
+2
+8
+8
+0
+9
+8
+8
+6
+8
+8
+8
+8
+9
+6
+6
+3
+1
+1
+0
+9
+6
+5
+3
+1
+7
+0
+1
+2
+1
+1
+8
+4
+0
+7
+0
+8
+2
+2
+8
+8
+3
+3
+2
+5
+0
+8
+8
+8
+8
+3
+4
+1
+9
+4
+1
+7
+8
+6
+6
+2
+4
+4
+7
+8
+2
+5
+8
+3
+4
+2
+6
+4
+3
+4
+2
+3
+5
+8
+0
+1
+3
+9
+1
+7
+7
+5
+8
+2
+0
+9
+0
+2
+9
+8
+1
+2
+3
+7
+7
+0
+7
+1
+3
+1
+9
+5
+4
+4
+6
+2
+0
+9
+9
+6
+6
+5
+7
+1
+5
+7
+7
+0
+1
+1
+4
+9
+6
+2
+5
+1
+0
+7
+7
+9
+1
+0
+2
+0
+3
+3
+1
+2
+5
+0
+1
+7
+2
+3
+4
+5
+4
+1
+9
+4
+1
+3
+1
+7
+4
+2
+7
+4
+5
+3
+0
+3
+9
+9
+2
+2
+6
+4
+7
+2
+7
+7
+9
+3
+3
+5
+5
+6
+1
+2
+6
+6
+3
+6
+4
+3
+0
+2
+5
+6
+6
+5
+6
+3
+9
+6
+0
+7
+2
+1
+3
+4
+9
+6
+7
+0
+2
+6
+4
+5
+9
+5
+9
+1
+7
+2
+0
+8
+1
+8
+8
+6
+6
+2
+0
+3
+0
+7
+8
+8
+5
+8
+2
+6
+8
+5
+6
+8
+8
+8
+1
+8
+8
+8
+8
+8
+8
+1
+9
+5
+8
+2
+4
+7
+4
+2
+3
+4
+1
+0
+5
+9
+8
+8
+4
+3
+8
+8
+0
+5
+7
+8
+9
+3
+2
+1
+8
+4
+1
+6
+6
+1
+5
+3
+7
+0
+1
+8
+3
+6
+6
+3
+6
+9
+9
+0
+3
+6
+6
+5
+7
+9
+2
+7
+3
+0
+2
+6
+1
+9
+0
+5
+3
+5
+3
+7
+4
+9
+9
+6
+1
+2
+3
+3
+5
+1
+7
+1
+7
+7
+2
+3
+7
+5
+9
+5
+4
+3
+2
+4
+5
+4
+6
+2
+0
+9
+1
+6
+6
+6
+6
+7
+4
+1
+4
+4
+0
+0
+0
+4
+2
+9
+1
+3
+2
+4
+5
+7
+1
+2
+2
+3
+4
+7
+4
+1
+0
+5
+9
+7
+0
+3
+4
+2
+0
+4
+9
+2
+5
+3
+7
+0
+6
+7
+3
+3
+2
+5
+6
+0
+0
+9
+9
+1
+6
+4
+1
+6
+5
+4
+6
+1
+3
+6
+6
+6
+6
+5
+9
+2
+3
+3
+5
+9
+7
+0
+9
+7
+6
+2
+5
+1
+5
+9
+1
+0
+4
+7
+7
+4
+7
+5
+9
+2
+4
+0
+4
+3
+1
+7
+7
+7
+5
+1
+3
+9
+2
+2
+9
+0
+3
+0
+1
+9
+0
+6
+6
+4
+6
+1
+2
+0
+5
+4
+8
+6
+3
+8
+8
+3
+8
+1
+8
+8
+8
+7
+8
+3
+8
+2
+1
+0
+7
+9
+9
+0
+1
+2
+6
+1
+3
+2
+7
+1
+6
+8
+2
+4
+8
+1
+3
+5
+0
+6
+0
+6
+6
+8
+3
+7
+1
+6
+8
+8
+6
+8
+4
+8
+2
+4
+8
+9
+0
+8
+3
+7
+7
+3
+2
+6
+9
+7
+7
+2
+4
+5
+4
+0
+9
+4
+5
+2
+2
+8
+8
+9
+2
+0
+5
+1
+8
+3
+1
+9
+7
+5
+6
+0
+8
+5
+2
+0
+9
+0
+4
+5
+3
+6
+6
+2
+9
+6
+6
+6
+3
+3
+0
+1
+5
+6
+4
+6
+3
+0
+5
+7
+9
+1
+2
+1
+3
+2
+1
+0
+4
+7
+2
+9
+3
+7
+0
+7
+7
+6
+6
+6
+9
+5
+1
+2
+1
+6
+6
+0
+1
+0
+7
+4
+2
+4
+0
+1
+6
+6
+6
+3
+0
+1
+7
+5
+9
+3
+5
+3
+0
+0
+0
+4
+1
+3
+9
+2
+1
+1
+0
+9
+9
+4
+9
+5
+7
+2
+1
+9
+9
+1
+3
+0
+7
+9
+2
+7
+5
+5
+3
+3
+1
+9
+6
+0
+9
+4
+7
+2
+2
+7
+5
+1
+0
+6
+3
+6
+6
+9
+4
+6
+9
+7
+4
+4
+7
+4
+9
+0
+6
+0
+5
+6
+4
+3
+9
+4
+9
+0
+7
+2
+5
+3
+1
+4
+2
+4
+3
+5
+5
+2
+7
+1
+4
+2
+1
+9
+4
+6
+4
+4
+6
+4
+7
+9
+7
+8
+1
+0
+4
+8
+5
+9
+6
+8
+8
+2
+1
+5
+3
+9
+2
+4
+5
+1
+2
+2
+0
+5
+9
+1
+5
+1
+5
+5
+2
+7
+9
+3
+0
+5
+1
+0
+3
+9
+9
+3
+0
+5
+2
+4
+6
+0
+9
+0
+1
+6
+6
+9
+7
+0
+4
+7
+0
+4
+7
+9
+6
+6
+6
+1
+6
+3
+5
+6
+5
+2
+3
+7
+7
+1
+4
+5
+4
+4
+3
+4
+5
+4
+5
+2
+7
+5
+6
+4
+1
+0
+5
+0
+9
+2
+4
+1
+3
+4
+7
+9
+0
+2
+3
+3
+1
+7
+2
+9
+3
+0
+0
+6
+6
+3
+4
+6
+1
+6
+2
+7
+4
+3
+9
+1
+2
+1
+3
+9
+2
+3
+5
+0
+5
+6
+3
+7
+7
+2
+1
+5
+4
+7
+3
+0
+5
+1
+9
+4
+7
+5
+0
+1
+5
+7
+9
+5
+2
+0
+4
+5
+2
+6
+6
+5
+4
+0
+1
+6
+3
+5
+7
+6
+5
+2
+4
+9
+4
+0
+2
+1
+6
+7
+5
+2
+9
+6
+3
+4
+0
+6
+1
+7
+9
+7
+3
+3
+7
+6
+7
+9
+9
+1
+4
+5
+1
+4
+0
+9
+9
+3
+2
+8
+0
+3
+8
+2
+5
+8
+8
+8
+2
+9
+8
+1
+6
+8
+7
+5
+8
+7
+0
+8
+8
+8
+8
+8
+8
+8
+4
+8
+7
+8
+0
+7
+4
+4
+5
+8
+8
+8
+2
+1
+9
+5
+8
+0
+7
+8
+3
+8
+7
+8
+0
+8
+0
+8
+3
+6
+6
+8
+8
+8
+8
+1
+0
+5
+9
+0
+2
+0
+6
+1
+4
+2
+3
+6
+6
+7
+2
+0
+1
+6
+9
+3
+7
+1
+8
+5
+3
+0
+5
+3
+4
+7
+1
+2
+3
+1
+3
+6
+5
+3
+1
+9
+6
+2
+7
+5
+1
+3
+0
+7
+5
+0
+2
+3
+4
+0
+4
+9
+5
+5
+1
+2
+1
+6
+6
+9
+6
+4
+9
+5
+3
+2
+0
+9
+9
+2
+4
+4
+7
+1
+2
+6
+0
+5
+6
+1
+8
+3
+1
+6
+0
+7
+5
+2
+7
+1
+4
+4
+9
+2
+1
+9
+0
+3
+0
+5
+2
+1
+6
+9
+2
+2
+5
+6
+6
+2
+3
+3
+4
+3
+2
+0
+1
+1
+0
+6
+6
+7
+9
+1
+7
+6
+6
+2
+3
+1
+5
+0
+2
+7
+1
+9
+5
+2
+0
+3
+1
+4
+2
+9
+3
+3
+2
+5
+4
+7
+7
+4
+3
+0
+1
+2
+1
+0
+4
+4
+9
+4
+3
+3
+2
+2
+5
+5
+4
+6
+5
+4
+0
+1
+2
+0
+9
+0
+2
+3
+5
+6
+1
+6
+7
+6
+5
+5
+4
+5
+8
+5
+9
+8
+8
+8
+8
+8
+8
+8
+8
+1
+8
+8
+8
+6
+0
+1
+9
+7
+2
+5
+7
+3
+5
+2
+0
+1
+0
+2
+2
+4
+2
+9
+9
+7
+7
+0
+4
+0
+4
+3
+9
+4
+1
+5
+6
+5
+6
+9
+2
+6
+7
+6
+3
+2
+8
+7
+5
+0
+4
+4
+3
+6
+3
+6
+6
+1
+0
+7
+7
+4
+3
+2
+9
+5
+7
+0
+1
+2
+7
+0
+9
+0
+9
+7
+7
+2
+0
+1
+9
+4
+1
+8
+1
+4
+3
+7
+7
+3
+1
+2
+4
+9
+0
+2
+1
+6
+6
+5
+6
+9
+7
+4
+2
+3
+6
+1
+5
+9
+1
+6
+0
+3
+4
+4
+6
+0
+9
+2
+3
+6
+4
+6
+1
+4
+9
+0
+3
+7
+1
+3
+4
+9
+3
+1
+0
+2
+1
+6
+1
+9
+9
+5
+3
+1
+5
+0
+5
+7
+7
+5
+3
+9
+2
+6
+6
+5
+4
+0
+3
+9
+1
+5
+9
+5
+1
+2
+6
+3
+5
+7
+2
+1
+3
+1
+5
+9
+4
+0
+9
+1
+4
+0
+3
+1
+9
+3
+0
+4
+5
+2
+3
+7
+9
+2
+1
+7
+5
+7
+7
+9
+4
+0
+2
+6
+6
+5
+3
+2
+1
+3
+4
+1
+8
+1
+3
+8
+8
+8
+8
+8
+8
+8
+8
+8
+0
+2
+8
+6
+6
+5
+6
+9
+3
+1
+2
+2
+1
+6
+5
+7
+3
+7
+7
+3
+2
+9
+8
+5
+8
+8
+1
+7
+5
+9
+7
+8
+8
+2
+3
+3
+5
+8
+4
+8
+4
+4
+0
+4
+0
+9
+8
+6
+5
+8
+6
+3
+9
+5
+4
+0
+5
+4
+5
+3
+2
+1
+8
+8
+1
+0
+7
+4
+9
+7
+8
+8
+3
+2
+0
+1
+9
+4
+2
+4
+6
+8
+7
+2
+9
+4
+8
+1
+2
+9
+3
+0
+7
+7
+4
+6
+4
+9
+1
+0
+5
+2
+5
+6
+6
+4
+6
+5
+7
+0
+2
+0
+1
+7
+3
+1
+6
+5
+6
+7
+2
+9
+5
+5
+3
+7
+1
+1
+5
+5
+9
+4
+9
+0
+6
+7
+7
+1
+4
+2
+1
+4
+2
+2
+4
+9
+3
+7
+4
+4
+7
+3
+2
+7
+0
+0
+3
+2
+4
+6
+4
+4
+5
+0
+3
+2
+4
+7
+7
+9
+9
+5
+3
+6
+0
+1
+0
+9
+9
+2
+3
+9
+1
+2
+5
+4
+5
+4
+3
+9
+7
+5
+2
+5
+4
+0
+0
+9
+1
+9
+9
+5
+4
+7
+3
+2
+6
+4
+0
+6
+2
+0
+3
+9
+9
+1
+6
+1
+7
+6
+2
+0
+9
+0
+4
+4
+1
+6
+4
+6
+6
+3
+7
+2
+7
+5
+3
+7
+9
+3
+1
+0
+2
+1
+7
+5
+4
+3
+5
+7
+0
+9
+2
+9
+1
+1
+7
+3
+4
+1
+7
+9
+3
+3
+5
+0
+7
+0
+1
+4
+3
+4
+6
+6
+2
+8
+0
+8
+5
+8
+3
+8
+8
+6
+2
+8
+0
+8
+0
+1
+5
+6
+8
+1
+0
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+2
+2
+5
+8
+2
+2
+4
+9
+0
+2
+0
+1
+6
+6
+5
+3
+4
+9
+6
+5
+3
+3
+6
+9
+6
+7
+7
+2
+3
+3
+0
+9
+2
+4
+6
+6
+2
+1
+3
+3
+4
+9
+1
+0
+5
+0
+3
+3
+1
+9
+4
+4
+1
+5
+0
+3
+7
+9
+5
+1
+4
+3
+6
+4
+9
+3
+5
+0
+5
+0
+4
+7
+7
+3
+2
+5
+1
+9
+2
+6
+6
+1
+7
+5
+3
+7
+3
+1
+6
+0
+1
+2
+6
+4
+3
+5
+9
+6
+6
+7
+7
+2
+5
+6
+3
+3
+2
+6
+5
+9
+0
+1
+3
+0
+7
+1
+7
+5
+1
+2
+9
+3
+5
+0
+4
+9
+7
+4
+3
+3
+4
+4
+9
+4
+6
+6
+2
+5
+2
+1
+9
+2
+0
+3
+3
+0
+1
+5
+9
+7
+2
+4
+7
+3
+4
+9
+9
+4
+3
+2
+4
+9
+8
+0
+0
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+0
+3
+2
+9
+9
+5
+3
+7
+3
+9
+0
+1
+9
+6
+1
+2
+5
+1
+9
+7
+2
+6
+6
+0
+8
+5
+9
+6
+1
+7
+7
+8
+7
+7
+2
+6
+8
+8
+5
+1
+8
+4
+1
+8
+8
+8
+8
+2
+8
+0
+9
+6
+2
+3
+0
+8
+4
+2
+4
+4
+5
+4
+2
+7
+0
+9
+2
+0
+8
+0
+1
+8
+8
+9
+9
+2
+4
+7
+4
+6
+5
+6
+3
+2
+7
+9
+0
+6
+2
+5
+3
+1
+2
+3
+9
+4
+0
+2
+3
+0
+7
+0
+5
+4
+9
+1
+2
+3
+8
+6
+6
+0
+4
+5
+3
+2
+3
+1
+9
+5
+0
+0
+6
+4
+2
+2
+9
+6
+1
+2
+0
+7
+5
+3
+9
+6
+4
+6
+4
+1
+0
+7
+7
+2
+5
+1
+4
+9
+6
+4
+9
+3
+2
+5
+7
+9
+4
+2
+4
+4
+0
+1
+2
+5
+0
+0
+0
+1
+5
+4
+1
+2
+3
+5
+9
+3
+4
+5
+1
+0
+2
+0
+3
+5
+2
+2
+4
+7
+9
+2
+6
+0
+6
+0
+2
+9
+5
+5
+3
+0
+1
+0
+6
+6
+7
+1
+3
+2
+5
+9
+9
+0
+1
+0
+3
+2
+5
+7
+7
+1
+2
+2
+6
+0
+2
+5
+4
+4
+3
+4
+5
+3
+5
+0
+9
+1
+4
+5
+2
+7
+7
+3
+0
+2
+4
+1
+4
+2
+6
+4
+5
+7
+7
+0
+0
+9
+4
+2
+9
+6
+5
+2
+3
+9
+4
+7
+2
+1
+7
+4
+1
+9
+0
+1
+8
+8
+0
+7
+8
+2
+5
+8
+8
+8
+1
+8
+8
+8
+9
+3
+8
+4
+4
+8
+8
+8
+9
+8
+6
+7
+8
+8
+8
+8
+3
+7
+7
+3
+4
+9
+8
+4
+1
+0
+5
+6
+6
+9
+0
+1
+9
+6
+6
+1
+5
+8
+1
+7
+7
+8
+2
+5
+8
+4
+8
+8
+9
+4
+4
+0
+1
+5
+9
+2
+4
+1
+7
+4
+6
+9
+9
+7
+5
+6
+6
+4
+2
+4
+9
+6
+6
+5
+2
+5
+4
+7
+4
+4
+3
+6
+0
+3
+6
+1
+5
+0
+5
+0
+1
+2
+7
+2
+0
+5
+1
+0
+2
+9
+2
+2
+9
+5
+3
+7
+7
+3
+5
+0
+1
+5
+3
+1
+3
+9
+9
+5
+7
+2
+7
+2
+6
+9
+9
+3
+6
+6
+5
+2
+3
+4
+5
+4
+6
+1
+6
+5
+1
+7
+9
+1
+2
+4
+5
+6
+6
+5
+6
+3
+4
+2
+7
+9
+3
+9
+3
+3
+0
+5
+2
+5
+0
+1
+9
+2
+1
+7
+7
+1
+2
+4
+0
+1
+0
+1
+0
+4
+8
+3
+5
+8
+8
+8
+9
+8
+8
+8
+8
+8
+8
+8
+9
+0
+0
+6
+2
+4
+7
+9
+2
+5
+3
+7
+0
+3
+4
+9
+0
+0
+2
+5
+3
+1
+5
+7
+7
+8
+8
+0
+3
+5
+6
+2
+1
+8
+8
+8
+1
+8
+7
+5
+2
+4
+5
+1
+6
+8
+1
+0
+4
+1
+2
+1
+5
+6
+3
+3
+4
+6
+4
+4
+1
+4
+3
+3
+5
+6
+7
+6
+6
+9
+8
+0
+9
+2
+1
+8
+4
+9
+4
+3
+9
+3
+0
+7
+4
+9
+9
+2
+1
+3
+7
+2
+0
+7
+0
+1
+2
+7
+8
+1
+4
+9
+0
+5
+1
+2
+2
+4
+5
+1
+9
+6
+0
+2
+0
+6
+5
+5
+3
+7
+4
+9
+4
+5
+0
+0
+3
+2
+5
+4
+1
+2
+0
+0
+3
+7
+7
+1
+4
+4
+2
+6
+3
+3
+0
+5
+4
+0
+7
+1
+2
+1
+0
+6
+9
+2
+4
+5
+4
+4
+3
+3
+0
+2
+1
+6
+3
+6
+6
+3
+5
+1
+2
+2
+1
+3
+4
+1
+9
+6
+6
+5
+2
+6
+3
+9
+9
+3
+1
+4
+0
+2
+7
+4
+9
+2
+0
+4
+0
+1
+5
+5
+9
+0
+1
+0
+7
+7
+3
+9
+3
+4
+0
+4
+0
+9
+1
+7
+7
+3
+7
+5
+6
+9
+6
+5
+9
+3
+4
+6
+6
+5
+2
+4
+5
+6
+6
+2
+2
+9
+4
+2
+2
+3
+0
+2
+0
+4
+3
+4
+2
+5
+7
+6
+5
+7
+0
+4
+1
+7
+7
+9
+9
+2
+5
+6
+0
+6
+6
+4
+9
+5
+2
+5
+8
+8
+8
+1
+8
+8
+6
+8
+2
+9
+5
+3
+8
+7
+1
+0
+8
+4
+1
+8
+8
+8
+8
+8
+8
+1
+8
+8
+1
+8
+2
+0
+8
+9
+4
+3
+4
+4
+8
+8
+2
+0
+7
+0
+5
+8
+0
+8
+8
+9
+8
+3
+8
+2
+5
+7
+6
+9
+2
+4
+8
+5
+6
+5
+4
+9
+9
+7
+6
+3
+1
+6
+0
+6
+9
+5
+4
+3
+6
+6
+6
+1
+9
+7
+7
+5
+6
+4
+5
+7
+9
+1
+0
+3
+4
+9
+1
+7
+1
+2
+0
+5
+0
+1
+5
+6
+3
+7
+7
+6
+4
+7
+6
+0
+6
+0
+6
+6
+6
+9
+9
+2
+9
+3
+7
+7
+5
+2
+9
+6
+3
+1
+2
+3
+0
+5
+0
+5
+3
+3
+2
+9
+1
+9
+9
+4
+1
+4
+5
+2
+5
+9
+9
+2
+4
+7
+1
+4
+7
+1
+9
+1
+4
+2
+3
+5
+7
+6
+6
+0
+1
+0
+3
+6
+4
+1
+9
+0
+0
+6
+6
+6
+6
+7
+7
+4
+7
+4
+3
+9
+2
+8
+8
+0
+6
+0
+7
+8
+9
+5
+2
+8
+8
+8
+8
+0
+9
+6
+8
+4
+6
+8
+8
+8
+9
+8
+8
+8
+7
+8
+8
+8
+2
+6
+6
+0
+2
+0
+3
+6
+8
+1
+7
+9
+7
+8
+1
+8
+8
+8
+8
+8
+8
+8
+4
+0
+8
+4
+7
+9
+8
+8
+5
+7
+4
+4
+0
+9
+9
+1
+7
+1
+5
+2
+4
+7
+9
+4
+6
+8
+1
+5
+2
+9
+1
+1
+5
+8
+8
+6
+6
+1
+6
+5
+1
+2
+3
+1
+7
+3
+2
+6
+6
+5
+6
+2
+5
+3
+1
+1
+2
+0
+4
+6
+2
+6
+4
+7
+7
+4
+0
+0
+0
+3
+9
+4
+0
+8
+5
+4
+7
+3
+2
+2
+2
+0
+4
+0
+3
+4
+9
+3
+2
+1
+7
+9
+3
+1
+9
+4
+5
+7
+1
+9
+6
+2
+4
+5
+4
+6
+6
+6
+3
+2
+1
+5
+4
+0
+9
+1
+3
+1
+4
+2
+4
+4
+9
+0
+1
+3
+5
+7
+7
+9
+9
+1
+9
+7
+2
+0
+5
+2
+6
+7
+7
+2
+0
+1
+0
+7
+5
+6
+6
+4
+6
+2
+7
+5
+1
+4
+6
+0
+1
+6
+2
+6
+7
+0
+3
+1
+5
+9
+1
+2
+9
+1
+4
+6
+7
+4
+9
+5
+0
+2
+0
+6
+4
+2
+9
+7
+7
+7
+0
+7
+5
+9
+2
+1
+9
+4
+1
+5
+3
+9
+5
+2
+4
+0
+8
+0
+2
+8
+8
+8
+8
+8
+8
+8
+8
+8
+3
+6
+8
+5
+2
+7
+3
+6
+9
+3
+1
+6
+6
+6
+6
+7
+7
+3
+7
+7
+8
+8
+8
+5
+8
+3
+8
+1
+8
+0
+8
+6
+6
+3
+2
+9
+4
+4
+3
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+9
+9
+5
+4
+1
+4
+2
+6
+9
+9
+6
+2
+7
+3
+5
+1
+2
+9
+7
+1
+8
+8
+0
+4
+0
+9
+1
+5
+4
+1
+3
+1
+1
+0
+2
+2
+5
+1
+9
+2
+3
+7
+0
+0
+2
+0
+7
+3
+3
+5
+8
+0
+0
+0
+1
+8
+6
+2
+5
+1
+6
+5
+7
+7
+3
+9
+2
+2
+0
+6
+9
+5
+6
+6
+3
+7
+2
+5
+5
+9
+2
+6
+6
+6
+6
+1
+9
+0
+7
+4
+4
+5
+4
+0
+9
+3
+4
+5
+3
+1
+1
+7
+0
+0
+7
+7
+1
+7
+3
+5
+6
+6
+9
+9
+5
+2
+6
+6
+1
+2
+1
+3
+6
+0
+2
+0
+7
+7
+6
+0
+5
+4
+3
+7
+9
+6
+4
+1
+7
+3
+3
+5
+2
+4
+9
+9
+6
+0
+3
+4
+4
+2
+4
+9
+7
+7
+3
+2
+9
+4
+1
+8
+0
+3
+8
+8
+8
+8
+8
+8
+8
+8
+4
+6
+2
+9
+1
+9
+5
+3
+7
+7
+1
+2
+6
+1
+7
+6
+3
+4
+5
+6
+5
+2
+8
+8
+6
+3
+7
+6
+8
+8
+2
+5
+5
+3
+1
+9
+0
+8
+1
+4
+5
+1
+4
+7
+2
+8
+0
+8
+0
+3
+8
+9
+2
+5
+9
+1
+7
+6
+3
+7
+5
+6
+6
+6
+4
+3
+3
+8
+0
+1
+6
+6
+8
+5
+3
+4
+1
+4
+0
+2
+0
+8
+3
+0
+2
+4
+4
+9
+4
+0
+7
+8
+3
+1
+9
+9
+5
+4
+4
+0
+8
+7
+2
+4
+7
+3
+7
+7
+4
+0
+9
+9
+6
+3
+3
+6
+9
+5
+1
+7
+5
+2
+0
+3
+5
+6
+5
+6
+1
+5
+6
+3
+4
+6
+2
+9
+6
+5
+1
+6
+3
+1
+0
+0
+2
+7
+5
+0
+0
+4
+3
+6
+4
+2
+6
+1
+9
+7
+0
+4
+0
+1
+1
+7
+9
+1
+2
+7
+5
+1
+4
+2
+9
+5
+9
+9
+1
+7
+0
+5
+0
+7
+7
+6
+2
+4
+4
+3
+4
+2
+0
+6
+9
+1
+9
+4
+3
+1
+0
+1
+0
+5
+7
+3
+1
+4
+4
+2
+5
+1
+0
+3
+2
+3
+7
+6
+2
+2
+5
+0
+0
+3
+3
+5
+6
+7
+4
+7
+3
+4
+4
+5
+9
+6
+2
+9
+6
+6
+6
+6
+9
+0
+6
+2
+1
+0
+1
+4
+3
+4
+6
+6
+5
+2
+0
+1
+3
+9
+7
+9
+1
+3
+5
+0
+9
+0
+2
+4
+7
+1
+4
+2
+5
+9
+7
+2
+8
+8
+8
+3
+0
+8
+5
+1
+7
+2
+9
+7
+8
+4
+0
+8
+5
+3
+1
+5
+8
+8
+8
+8
+6
+7
+8
+3
+1
+8
+8
+8
+9
+8
+0
+2
+0
+8
+8
+5
+2
+9
+1
+3
+3
+1
+0
+7
+5
+2
+7
+4
+3
+8
+8
+8
+1
+8
+8
+8
+7
+8
+6
+6
+4
+9
+8
+2
+2
+7
+3
+4
+2
+7
+4
+6
+0
+2
+3
+6
+0
+9
+4
+3
+1
+0
+6
+6
+7
+9
+5
+3
+3
+4
+7
+1
+1
+5
+6
+2
+2
+0
+9
+5
+5
+2
+7
+1
+1
+2
+9
+0
+1
+9
+5
+3
+7
+5
+9
+0
+0
+1
+2
+7
+5
+3
+9
+2
+3
+1
+4
+7
+2
+3
+5
+9
+0
+5
+1
+5
+6
+2
+1
+9
+0
+4
+1
+5
+4
+7
+9
+6
+3
+9
+5
+4
+1
+3
+4
+2
+2
+9
+4
+1
+5
+9
+3
+2
+2
+6
+1
+3
+7
+9
+6
+5
+4
+1
+7
+7
+6
+4
+4
+6
+4
+0
+6
+6
+9
+3
+2
+4
+6
+8
+5
+2
+8
+5
+8
+8
+8
+8
+8
+8
+8
+8
+8
+1
+0
+2
+6
+6
+1
+9
+5
+9
+3
+7
+0
+5
+0
+9
+2
+7
+1
+8
+9
+2
+5
+0
+8
+3
+2
+8
+9
+7
+6
+6
+8
+5
+8
+2
+0
+4
+0
+8
+1
+3
+5
+1
+9
+6
+8
+8
+2
+3
+4
+1
+5
+9
+7
+6
+6
+0
+2
+4
+4
+9
+8
+2
+1
+3
+5
+2
+3
+6
+4
+1
+8
+3
+8
+8
+7
+0
+1
+0
+4
+2
+9
+4
+3
+5
+6
+6
+9
+0
+7
+9
+3
+2
+2
+4
+9
+5
+2
+0
+6
+6
+8
+2
+4
+3
+1
+7
+0
+0
+0
+0
+2
+3
+0
+3
+2
+6
+7
+7
+9
+2
+2
+3
+0
+1
+5
+2
+9
+9
+4
+9
+3
+8
+1
+2
+5
+4
+9
+5
+7
+5
+6
+6
+6
+6
+1
+4
+2
+5
+4
+1
+7
+7
+6
+6
+3
+4
+2
+2
+6
+5
+6
+6
+3
+4
+7
+2
+1
+9
+0
+1
+5
+1
+3
+5
+2
+9
+7
+0
+6
+7
+9
+5
+3
+2
+2
+4
+4
+0
+2
+0
+3
+9
+7
+7
+1
+3
+3
+2
+5
+9
+1
+3
+2
+3
+9
+6
+2
+0
+6
+0
+9
+9
+3
+9
+2
+7
+2
+5
+5
+0
+0
+0
+4
+2
+2
+4
+4
+0
+2
+7
+7
+5
+1
+2
+9
+9
+3
+1
+0
+0
+5
+7
+0
+4
+0
+4
+2
+2
+4
+1
+9
+2
+5
+3
+0
+2
+2
+7
+9
+9
+1
+6
+3
+0
+0
+5
+6
+9
+4
+7
+3
+1
+1
+6
+7
+8
+8
+8
+2
+8
+0
+8
+5
+1
+7
+7
+8
+8
+9
+8
+7
+7
+8
+8
+8
+8
+8
+1
+8
+8
+8
+8
+8
+8
+3
+9
+2
+0
+8
+5
+8
+3
+3
+9
+8
+2
+5
+8
+7
+3
+3
+9
+1
+8
+8
+1
+5
+4
+6
+2
+4
+8
+7
+8
+6
+7
+4
+8
+7
+7
+9
+0
+2
+4
+3
+8
+4
+8
+9
+5
+0
+0
+7
+1
+4
+2
+9
+3
+8
+5
+3
+6
+8
+4
+9
+4
+5
+6
+5
+0
+5
+4
+9
+9
+1
+3
+6
+1
+6
+5
+5
+9
+7
+7
+6
+0
+7
+6
+9
+6
+6
+3
+3
+5
+0
+0
+7
+0
+7
+3
+1
+6
+3
+5
+5
+9
+2
+3
+7
+7
+2
+1
+0
+5
+4
+2
+1
+4
+3
+2
+4
+9
+1
+5
+7
+1
+3
+4
+6
+4
+5
+3
+5
+3
+9
+4
+3
+4
+2
+1
+6
+6
+7
+2
+3
+9
+1
+4
+2
+3
+9
+1
+2
+1
+6
+6
+0
+5
+9
+7
+1
+2
+1
+3
+0
+8
+3
+7
+8
+8
+8
+8
+8
+5
+8
+8
+8
+8
+2
+8
+7
+7
+3
+5
+0
+6
+5
+2
+9
+0
+3
+9
+7
+4
+0
+5
+6
+9
+8
+6
+1
+8
+8
+0
+5
+9
+2
+8
+7
+5
+8
+1
+8
+3
+8
+7
+8
+4
+4
+8
+2
+3
+8
+8
+5
+7
+8
+8
+1
+9
+1
+3
+3
+1
+5
+4
+7
+4
+4
+1
+6
+6
+8
+2
+1
+9
+4
+5
+3
+6
+1
+8
+2
+1
+6
+6
+3
+4
+7
+0
+9
+5
+0
+3
+0
+7
+6
+1
+5
+9
+2
+7
+2
+5
+0
+4
+6
+9
+1
+2
+2
+5
+9
+1
+2
+9
+7
+7
+1
+2
+3
+8
+5
+2
+0
+1
+0
+2
+5
+6
+7
+5
+1
+3
+4
+9
+0
+1
+4
+1
+6
+3
+9
+9
+0
+4
+0
+7
+5
+2
+7
+5
+7
+7
+1
+4
+9
+3
+4
+2
+1
+5
+7
+1
+9
+4
+0
+3
+4
+1
+0
+5
+2
+0
+1
+9
+3
+2
+7
+7
+7
+7
+5
+3
+6
+6
+1
+2
+9
+0
+7
+2
+5
+7
+3
+5
+6
+9
+4
+3
+2
+6
+6
+6
+9
+5
+5
+3
+1
+0
+3
+1
+5
+1
+2
+3
+4
+5
+6
+2
+4
+9
+6
+4
+7
+7
+0
+5
+2
+9
+7
+5
+2
+3
+3
+7
+1
+9
+7
+1
+4
+3
+4
+2
+0
+9
+6
+6
+5
+4
+2
+6
+6
+6
+5
+4
+4
+3
+4
+2
+7
+0
+4
+1
+9
+3
+3
+1
+2
+5
+7
+7
+9
+4
+3
+4
+5
+7
+4
+5
+9
+2
+8
+8
+3
+8
+8
+8
+8
+9
+8
+2
+3
+8
+6
+4
+6
+1
+5
+8
+0
+4
+6
+7
+8
+9
+8
+8
+8
+5
+8
+8
+0
+9
+1
+7
+1
+4
+9
+2
+6
+0
+0
+2
+3
+1
+9
+7
+2
+9
+4
+0
+3
+5
+8
+8
+1
+4
+8
+1
+4
+2
+4
+5
+8
+9
+2
+4
+7
+0
+9
+2
+8
+5
+5
+3
+0
+4
+7
+9
+4
+7
+5
+3
+1
+0
+3
+0
+4
+9
+6
+6
+3
+6
+1
+7
+0
+4
+0
+7
+9
+2
+3
+4
+7
+3
+4
+5
+0
+9
+3
+2
+2
+5
+7
+5
+9
+9
+0
+9
+7
+7
+1
+6
+2
+9
+6
+5
+6
+6
+9
+5
+5
+3
+0
+6
+1
+5
+9
+1
+6
+3
+7
+2
+5
+1
+9
+4
+4
+6
+4
+5
+0
+6
+9
+3
+2
+4
+3
+4
+4
+2
+1
+9
+6
+4
+5
+4
+3
+1
+4
+9
+0
+1
+1
+3
+7
+7
+9
+5
+7
+3
+3
+0
+3
+4
+9
+9
+5
+3
+6
+5
+3
+6
+2
+9
+0
+0
+2
+3
+3
+1
+3
+7
+7
+7
+6
+3
+9
+6
+5
+4
+4
+3
+4
+3
+6
+0
+7
+0
+6
+5
+1
+3
+7
+2
+5
+0
+8
+2
+8
+5
+3
+7
+6
+6
+1
+0
+5
+0
+3
+9
+8
+2
+8
+4
+7
+4
+6
+9
+8
+5
+8
+8
+8
+8
+2
+0
+7
+6
+6
+6
+1
+3
+1
+4
+2
+4
+5
+8
+4
+2
+0
+1
+7
+2
+8
+7
+9
+3
+3
+5
+5
+8
+2
+4
+9
+1
+4
+1
+1
+0
+5
+2
+2
+9
+0
+5
+3
+2
+0
+1
+7
+9
+7
+6
+3
+8
+7
+7
+9
+6
+1
+9
+3
+1
+0
+6
+0
+9
+7
+2
+4
+6
+3
+2
+2
+0
+6
+1
+7
+7
+5
+7
+9
+2
+1
+0
+3
+4
+1
+6
+4
+1
+2
+3
+5
+0
+2
+4
+1
+4
+4
+7
+5
+4
+2
+0
+4
+0
+4
+6
+9
+9
+1
+5
+2
+7
+4
+0
+7
+1
+6
+7
+5
+2
+4
+3
+9
+0
+1
+9
+7
+7
+2
+3
+9
+9
+3
+5
+1
+7
+0
+2
+0
+3
+5
+7
+2
+5
+7
+1
+9
+0
+3
+9
+1
+2
+1
+5
+9
+6
+3
+0
+7
+6
+5
+7
+1
+4
+4
+2
+3
+6
+9
+2
+7
+3
+0
+1
+0
+2
+9
+0
+6
+3
+0
+6
+0
+4
+1
+6
+4
+1
+3
+7
+1
+0
+9
+4
+4
+8
+6
+3
+8
+8
+8
+9
+8
+8
+8
+8
+8
+5
+8
+9
+9
+2
+1
+5
+3
+1
+0
+5
+5
+9
+7
+0
+6
+6
+2
+2
+8
+8
+6
+8
+8
+8
+2
+8
+7
+7
+9
+5
+8
+8
+8
+8
+2
+8
+3
+1
+8
+8
+8
+8
+8
+8
+8
+8
+8
+6
+7
+5
+0
+0
+9
+4
+1
+7
+1
+2
+8
+1
+7
+2
+6
+5
+3
+1
+2
+8
+5
+3
+6
+0
+8
+4
+8
+2
+9
+7
+4
+8
+5
+0
+6
+6
+2
+9
+0
+3
+6
+7
+2
+0
+9
+5
+2
+4
+0
+8
+2
+2
+9
+9
+5
+7
+1
+7
+0
+1
+9
+9
+8
+0
+3
+4
+9
+7
+2
+9
+5
+3
+3
+1
+9
+4
+5
+2
+2
+6
+1
+5
+2
+7
+1
+9
+4
+1
+7
+4
+6
+6
+4
+6
+0
+3
+5
+0
+4
+0
+2
+1
+7
+3
+5
+9
+3
+9
+2
+5
+5
+0
+9
+9
+0
+1
+4
+2
+4
+3
+9
+7
+6
+6
+7
+4
+6
+4
+4
+9
+3
+5
+0
+0
+6
+0
+7
+3
+5
+1
+6
+6
+9
+5
+0
+1
+3
+6
+6
+6
+2
+5
+7
+7
+3
+0
+4
+0
+4
+2
+5
+9
+1
+4
+3
+7
+9
+1
+2
+3
+0
+7
+3
+1
+9
+7
+4
+2
+7
+0
+4
+7
+4
+2
+1
+3
+3
+1
+0
+1
+9
+6
+9
+5
+0
+5
+3
+4
+9
+4
+2
+1
+4
+3
+0
+6
+9
+9
+1
+4
+2
+6
+7
+5
+2
+9
+6
+6
+5
+3
+3
+6
+7
+9
+0
+7
+5
+1
+5
+9
+2
+5
+4
+1
+9
+7
+0
+7
+0
+3
+1
+3
+3
+1
+0
+9
+0
+1
+2
+1
+9
+6
+4
+9
+1
+6
+0
+2
+2
+9
+4
+1
+5
+6
+0
+0
+6
+9
+5
+6
+6
+1
+6
+5
+6
+1
+4
+6
+4
+7
+2
+5
+7
+6
+7
+4
+2
+0
+4
+2
+2
+0
+6
+4
+7
+4
+1
+7
+4
+2
+0
+1
+5
+7
+5
+4
+9
+9
+3
+0
+1
+7
+2
+7
+9
+3
+3
+2
+6
+6
+0
+6
+2
+7
+0
+5
+0
+2
+9
+0
+6
+6
+5
+4
+3
+4
+0
+5
+1
+4
+4
+7
+3
+6
+9
+7
+5
+3
+6
+2
+3
+5
+9
+4
+5
+3
+0
+2
+3
+7
+7
+1
+2
+3
+3
+5
+3
+9
+1
+6
+5
+2
+3
+4
+5
+1
+4
+6
+4
+3
+7
+6
+1
+9
+1
+4
+6
+8
+9
+2
+8
+8
+7
+8
+8
+4
+9
+3
+4
+5
+8
+8
+8
+8
+4
+1
+8
+8
+8
+8
+8
+8
+0
+8
+8
+8
+5
+8
+7
+8
+9
+0
+2
+0
+3
+8
+4
+1
+9
+9
+6
+2
+3
+0
+7
+7
+9
+4
+1
+8
+5
+0
+6
+0
+6
+6
+8
+8
+3
+1
+4
+0
+1
+9
+2
+3
+0
+4
+0
+2
+4
+9
+7
+5
+7
+7
+1
+0
+7
+9
+4
+3
+2
+5
+5
+7
+0
+9
+7
+7
+4
+2
+7
+4
+4
+7
+6
+3
+9
+1
+0
+9
+6
+4
+2
+4
+1
+7
+6
+7
+6
+6
+5
+1
+7
+1
+4
+5
+0
+3
+1
+7
+9
+5
+0
+5
+7
+1
+1
+0
+9
+2
+3
+4
+1
+7
+7
+1
+9
+9
+4
+1
+5
+7
+0
+3
+9
+9
+1
+0
+1
+4
+6
+7
+6
+9
+5
+4
+4
+2
+4
+5
+1
+3
+6
+0
+7
+6
+9
+2
+7
+3
+3
+6
+2
+4
+5
+4
+6
+9
+4
+5
+2
+0
+0
+0
+2
+3
+6
+6
+6
+2
+9
+1
+6
+4
+2
+3
+5
+7
+4
+9
+1
+5
+1
+2
+3
+0
+9
+0
+2
+5
+7
+7
+3
+1
+9
+6
+5
+0
+6
+6
+3
+6
+4
+5
+5
+1
+1
+7
+3
+2
+0
+4
+1
+7
+2
+2
+4
+0
+5
+1
+5
+3
+3
+2
+9
+9
+1
+9
+1
+5
+8
+8
+0
+4
+8
+4
+8
+8
+5
+8
+8
+2
+8
+8
+0
+6
+2
+1
+5
+9
+1
+5
+0
+4
+9
+3
+6
+6
+4
+1
+5
+3
+8
+6
+2
+8
+3
+7
+6
+6
+8
+9
+7
+5
+2
+4
+4
+8
+0
+8
+8
+8
+3
+2
+8
+8
+8
+9
+7
+7
+3
+8
+8
+5
+7
+5
+1
+0
+0
+0
+7
+7
+2
+9
+5
+3
+2
+5
+9
+0
+4
+9
+5
+3
+7
+2
+7
+4
+6
+4
+4
+3
+3
+8
+5
+6
+0
+0
+2
+1
+3
+0
+2
+1
+1
+7
+0
+0
+7
+0
+5
+2
+5
+4
+1
+0
+3
+1
+9
+9
+6
+6
+3
+5
+1
+4
+4
+9
+5
+3
+2
+1
+9
+6
+2
+9
+4
+7
+1
+2
+9
+1
+3
+4
+2
+1
+6
+3
+9
+2
+0
+0
+1
+2
+5
+3
+9
+5
+7
+9
+1
+0
+2
+6
+9
+3
+0
+5
+0
+1
+7
+2
+2
+9
+5
+9
+5
+4
+4
+3
+1
+2
+3
+9
+7
+2
+0
+7
+0
+9
+3
+6
+8
+8
+2
+4
+8
+4
+8
+8
+4
+8
+8
+1
+8
+8
+8
+8
+2
+6
+0
+5
+7
+7
+6
+6
+0
+4
+5
+1
+4
+5
+2
+5
+8
+8
+5
+8
+8
+0
+8
+1
+8
+9
+2
+7
+4
+8
+1
+0
+8
+8
+1
+2
+8
+1
+8
+8
+8
+7
+8
+8
+1
+8
+8
+8
+6
+9
+8
+6
+5
+7
+2
+7
+3
+9
+2
+8
+8
+1
+8
+3
+3
+9
+8
+2
+2
+7
+4
+8
+1
+9
+7
+0
+0
+0
+8
+8
+4
+7
+2
+7
+8
+0
+9
+4
+5
+1
+4
+2
+6
+6
+5
+2
+5
+9
+0
+8
+2
+6
+7
+7
+6
+9
+6
+5
+5
+2
+9
+1
+7
+3
+1
+7
+5
+1
+6
+9
+4
+3
+3
+2
+1
+7
+9
+9
+7
+5
+3
+7
+2
+2
+0
+3
+0
+2
+3
+1
+4
+5
+9
+5
+7
+2
+5
+7
+6
+5
+7
+1
+1
+3
+9
+6
+4
+9
+1
+3
+4
+0
+1
+6
+7
+1
+0
+2
+2
+2
+3
+5
+2
+9
+1
+3
+7
+0
+4
+1
+3
+9
+5
+3
+4
+3
+1
+4
+3
+0
+2
+5
+7
+3
+9
+0
+2
+0
+7
+2
+5
+3
+9
+5
+6
+5
+6
+0
+4
+2
+7
+3
+0
+9
+1
+5
+6
+1
+6
+3
+7
+7
+0
+7
+6
+6
+7
+9
+3
+6
+6
+6
+2
+1
+9
+9
+3
+7
+4
+1
+9
+0
+6
+6
+5
+1
+0
+1
+0
+7
+2
+9
+1
+0
+7
+5
+0
+5
+9
+2
+2
+4
+4
+4
+5
+7
+0
+9
+6
+6
+3
+4
+8
+8
+6
+7
+8
+4
+8
+8
+8
+8
+8
+8
+5
+8
+3
+8
+7
+9
+1
+3
+3
+1
+5
+4
+2
+5
+0
+2
+0
+7
+9
+9
+8
+8
+8
+5
+5
+3
+3
+9
+8
+7
+1
+4
+9
+3
+7
+7
+8
+1
+2
+8
+6
+6
+3
+9
+1
+0
+8
+2
+7
+8
+3
+9
+3
+6
+5
+8
+9
+2
+6
+6
+7
+1
+7
+7
+9
+3
+2
+9
+4
+0
+2
+8
+9
+3
+5
+4
+7
+4
+4
+0
+4
+3
+8
+1
+0
+4
+4
+5
+4
+9
+5
+3
+3
+5
+7
+4
+0
+6
+4
+5
+3
+5
+0
+2
+0
+9
+4
+2
+5
+6
+7
+6
+2
+9
+0
+3
+7
+5
+9
+9
+5
+4
+0
+1
+3
+2
+5
+9
+7
+5
+1
+4
+7
+7
+1
+7
+9
+1
+2
+5
+6
+6
+9
+2
+1
+3
+5
+6
+2
+4
+9
+1
+6
+6
+1
+3
+3
+2
+1
+5
+7
+1
+7
+7
+3
+4
+6
+9
+0
+3
+5
+0
+1
+5
+9
+9
+7
+7
+0
+3
+8
+8
+3
+4
+8
+8
+8
+8
+4
+7
+8
+8
+8
+8
+8
+8
+9
+0
+5
+9
+1
+3
+1
+5
+9
+4
+3
+2
+4
+0
+6
+6
+1
+9
+8
+8
+8
+2
+8
+8
+6
+9
+7
+1
+3
+4
+4
+8
+6
+3
+8
+0
+5
+0
+8
+8
+7
+9
+8
+2
+2
+8
+8
+8
+0
+3
+3
+8
+9
+8
+8
+1
+6
+6
+0
+8
+9
+2
+7
+6
+8
+8
+1
+0
+6
+1
+4
+6
+8
+8
+2
+8
+9
+8
+7
+7
+4
+6
+0
+6
+0
+9
+6
+4
+0
+4
+4
+7
+3
+2
+0
+1
+8
+1
+4
+1
+9
+7
+0
+9
+0
+7
+2
+4
+3
+4
+4
+5
+2
+5
+1
+3
+2
+7
+1
+7
+5
+2
+5
+0
+6
+0
+3
+6
+4
+3
+5
+0
+1
+5
+2
+5
+6
+6
+7
+3
+3
+9
+5
+2
+2
+6
+9
+0
+6
+0
+7
+6
+6
+2
+9
+1
+1
+3
+0
+7
+1
+4
+4
+3
+4
+9
+3
+0
+0
+0
+9
+4
+2
+4
+4
+5
+9
+4
+4
+2
+4
+7
+3
+6
+2
+9
+7
+4
+3
+2
+1
+4
+9
+9
+1
+3
+3
+1
+4
+0
+4
+0
+7
+7
+1
+0
+3
+4
+4
+9
+6
+1
+2
+3
+9
+7
+0
+4
+1
+5
+4
+1
+9
+1
+0
+2
+4
+5
+7
+3
+3
+7
+1
+6
+0
+4
+0
+3
+2
+5
+7
+5
+4
+2
+2
+0
+1
+0
+2
+1
+6
+6
+7
+2
+9
+9
+3
+2
+0
+6
+0
+5
+7
+0
+4
+0
+2
+2
+5
+3
+9
+4
+8
+8
+7
+2
+8
+8
+5
+0
+8
+0
+3
+1
+4
+7
+8
+9
+8
+8
+7
+5
+8
+8
+8
+8
+8
+8
+8
+8
+6
+8
+8
+8
+7
+7
+2
+6
+8
+8
+8
+0
+5
+0
+9
+2
+2
+4
+1
+3
+5
+0
+1
+8
+8
+1
+7
+7
+8
+8
+9
+0
+1
+0
+8
+3
+0
+8
+2
+7
+1
+0
+5
+2
+2
+5
+1
+9
+2
+7
+6
+6
+7
+1
+9
+5
+6
+2
+8
+4
+1
+4
+3
+9
+4
+7
+0
+5
+6
+6
+0
+9
+4
+6
+6
+5
+9
+1
+3
+4
+2
+4
+4
+7
+6
+3
+3
+9
+1
+2
+0
+5
+0
+3
+3
+9
+7
+0
+2
+1
+9
+0
+1
+3
+3
+1
+5
+2
+7
+5
+7
+1
+1
+6
+1
+0
+4
+2
+1
+5
+3
+0
+5
+4
+9
+7
+6
+6
+3
+4
+2
+0
+7
+3
+2
+7
+5
+5
+7
+1
+1
+0
+3
+2
+3
+6
+1
+5
+2
+3
+1
+5
+4
+1
+9
+7
+5
+2
+3
+6
+1
+0
+9
+6
+8
+8
+5
+7
+8
+5
+8
+6
+4
+8
+8
+0
+8
+8
+8
+8
+2
+7
+6
+0
+3
+0
+5
+4
+1
+4
+4
+5
+4
+7
+9
+9
+8
+8
+2
+8
+5
+8
+3
+9
+8
+1
+8
+2
+7
+4
+3
+5
+2
+5
+7
+3
+8
+8
+8
+9
+5
+8
+8
+8
+7
+7
+6
+6
+1
+0
+2
+4
+9
+3
+0
+2
+7
+7
+6
+1
+2
+3
+5
+9
+6
+6
+8
+8
+9
+2
+3
+4
+7
+4
+0
+5
+0
+3
+7
+9
+4
+0
+7
+5
+5
+9
+3
+1
+6
+4
+4
+9
+7
+7
+1
+2
+0
+6
+1
+9
+2
+1
+3
+6
+5
+2
+0
+9
+1
+2
+3
+0
+3
+6
+6
+0
+0
+0
+2
+5
+3
+7
+1
+2
+5
+1
+7
+0
+2
+1
+9
+9
+2
+3
+5
+0
+9
+5
+1
+9
+4
+3
+7
+7
+9
+9
+2
+5
+5
+7
+2
+3
+0
+9
+7
+7
+6
+6
+6
+2
+3
+0
+4
+9
+2
+6
+1
+7
+5
+7
+6
+4
+0
+4
+4
+3
+1
+6
+3
+4
+7
+7
+2
+6
+4
+9
+0
+1
+0
+5
+5
+4
+2
+9
+0
+6
+0
+7
+5
+3
+9
+2
+3
+5
+4
+3
+0
+3
+0
+2
+0
+5
+6
+6
+6
+1
+7
+4
+0
+7
+4
+9
+1
+5
+3
+5
+1
+2
+0
+1
+6
+5
+2
+7
+7
+7
+1
+2
+7
+3
+5
+2
+4
+1
+7
+9
+2
+0
+0
+3
+7
+2
+5
+1
+5
+2
+5
+1
+3
+2
+9
+9
+4
+3
+2
+6
+3
+7
+9
+9
+6
+4
+8
+8
+9
+8
+3
+6
+8
+7
+8
+4
+5
+8
+4
+8
+8
+8
+8
+8
+3
+6
+8
+8
+8
+5
+2
+8
+8
+8
+3
+8
+8
+0
+1
+8
+0
+3
+0
+5
+2
+8
+4
+0
+2
+9
+5
+7
+0
+2
+1
+7
+9
+2
+2
+8
+7
+8
+0
+5
+9
+3
+6
+2
+8
+6
+6
+9
+0
+6
+7
+2
+7
+1
+1
+9
+5
+3
+3
+5
+9
+5
+4
+9
+1
+8
+3
+1
+0
+4
+0
+4
+4
+8
+4
+6
+5
+8
+5
+7
+4
+1
+4
+2
+3
+5
+9
+6
+1
+5
+5
+4
+6
+6
+0
+1
+8
+3
+6
+6
+9
+7
+1
+5
+6
+3
+2
+1
+9
+0
+6
+6
+7
+7
+0
+0
+1
+9
+6
+1
+5
+1
+7
+5
+2
+0
+4
+5
+7
+7
+1
+3
+3
+9
+2
+0
+5
+3
+2
+3
+5
+9
+1
+4
+4
+4
+9
+5
+0
+9
+0
+7
+2
+1
+6
+6
+2
+3
+3
+9
+1
+2
+2
+4
+5
+2
+3
+5
+6
+6
+7
+3
+7
+4
+6
+0
+3
+7
+2
+4
+9
+5
+1
+2
+3
+0
+7
+7
+5
+9
+7
+9
+7
+4
+0
+4
+4
+3
+3
+9
+2
+5
+6
+6
+9
+6
+8
+8
+8
+0
+2
+8
+8
+4
+6
+4
+1
+8
+3
+1
+7
+7
+8
+6
+3
+5
+8
+8
+8
+8
+1
+0
+8
+8
+7
+5
+8
+9
+6
+6
+6
+6
+9
+4
+1
+5
+7
+1
+7
+3
+9
+2
+5
+4
+5
+8
+8
+8
+3
+5
+2
+9
+7
+7
+2
+8
+9
+8
+8
+1
+4
+4
+1
+3
+2
+9
+3
+7
+8
+5
+7
+3
+6
+9
+6
+6
+1
+4
+0
+3
+6
+6
+2
+0
+6
+0
+5
+7
+9
+5
+0
+2
+2
+4
+5
+3
+4
+0
+4
+2
+9
+7
+7
+4
+6
+6
+4
+0
+5
+2
+0
+9
+3
+4
+4
+1
+4
+7
+6
+3
+3
+6
+7
+4
+9
+0
+9
+1
+5
+7
+6
+0
+2
+0
+1
+9
+4
+3
+3
+1
+9
+1
+6
+3
+4
+7
+3
+6
+7
+5
+5
+0
+0
+0
+2
+5
+0
+9
+4
+2
+7
+3
+1
+7
+3
+9
+0
+1
+0
+2
+5
+0
+5
+9
+0
+4
+1
+7
+4
+7
+4
+9
+2
+5
+5
+3
+2
+4
+7
+7
+0
+2
+0
+6
+9
+3
+2
+4
+6
+6
+4
+2
+9
+3
+3
+5
+1
+6
+4
+3
+0
+6
+0
+9
+2
+1
+1
+5
+4
+2
+3
+1
+0
+1
+7
+7
+7
+7
+6
+6
+1
+2
+2
+9
+5
+6
+6
+6
+5
+4
+9
+7
+5
+1
+0
+6
+7
+5
+9
+0
+1
+4
+8
+8
+2
+4
+8
+8
+8
+8
+8
+8
+3
+8
+8
+1
+8
+5
+4
+1
+0
+0
+9
+9
+7
+3
+1
+4
+4
+4
+4
+6
+2
+3
+8
+3
+2
+7
+4
+8
+1
+2
+8
+6
+9
+4
+2
+4
+6
+6
+8
+7
+9
+8
+1
+2
+8
+6
+8
+0
+9
+8
+8
+8
+8
+1
+6
+6
+1
+9
+3
+1
+0
+2
+0
+5
+9
+9
+7
+0
+7
+5
+4
+5
+7
+8
+8
+2
+8
+4
+5
+3
+0
+1
+3
+7
+2
+7
+7
+6
+5
+7
+6
+5
+0
+6
+0
+3
+6
+2
+3
+0
+9
+2
+0
+3
+4
+6
+2
+0
+7
+1
+9
+5
+0
+4
+0
+4
+9
+0
+9
+3
+7
+1
+3
+0
+2
+2
+4
+5
+1
+3
+7
+1
+9
+2
+2
+1
+7
+7
+3
+2
+9
+0
+1
+2
+1
+6
+3
+7
+9
+6
+1
+4
+5
+3
+6
+5
+2
+0
+7
+1
+6
+2
+2
+4
+7
+9
+2
+4
+6
+3
+4
+2
+5
+9
+7
+2
+0
+0
+0
+0
+7
+7
+0
+6
+1
+5
+9
+4
+4
+9
+4
+5
+0
+7
+0
+3
+3
+5
+2
+5
+0
+3
+9
+2
+3
+9
+5
+7
+4
+1
+9
+3
+6
+6
+8
+5
+9
+8
+8
+8
+3
+4
+0
+4
+2
+8
+4
+5
+1
+2
+8
+8
+5
+2
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+6
+0
+8
+7
+7
+1
+3
+2
+8
+6
+6
+0
+9
+7
+1
+6
+2
+7
+1
+9
+7
+5
+8
+6
+6
+1
+5
+9
+8
+8
+3
+0
+8
+4
+5
+6
+9
+5
+3
+1
+0
+3
+1
+5
+9
+2
+5
+7
+7
+2
+4
+5
+9
+2
+3
+1
+5
+3
+2
+9
+9
+7
+6
+4
+1
+9
+0
+1
+4
+7
+1
+2
+3
+7
+4
+0
+5
+1
+6
+6
+2
+1
+2
+1
+0
+2
+0
+5
+3
+9
+7
+6
+1
+4
+3
+0
+0
+3
+2
+2
+5
+5
+3
+9
+3
+5
+4
+0
+7
+7
+6
+1
+6
+3
+9
+7
+0
+0
+6
+9
+9
+3
+6
+6
+6
+7
+7
+1
+0
+5
+4
+4
+1
+9
+6
+6
+6
+7
+7
+1
+5
+9
+1
+0
+9
+3
+1
+6
+2
+5
+4
+4
+9
+1
+7
+1
+7
+4
+2
+7
+4
+4
+2
+3
+5
+9
+7
+1
+4
+5
+1
+7
+0
+3
+9
+9
+2
+0
+4
+5
+2
+1
+5
+1
+5
+7
+3
+0
+7
+9
+2
+5
+1
+5
+7
+1
+0
+6
+0
+7
+7
+6
+6
+2
+3
+1
+9
+0
+0
+1
+3
+6
+2
+3
+4
+4
+0
+2
+0
+3
+1
+3
+9
+1
+5
+8
+8
+0
+4
+8
+0
+8
+8
+8
+8
+6
+8
+8
+8
+1
+8
+9
+3
+2
+9
+6
+5
+6
+0
+9
+7
+4
+2
+3
+2
+1
+3
+8
+9
+6
+1
+7
+7
+5
+7
+0
+9
+1
+3
+8
+1
+4
+8
+8
+1
+2
+5
+8
+8
+8
+8
+1
+9
+7
+3
+6
+6
+8
+5
+0
+7
+8
+0
+8
+2
+7
+4
+5
+6
+5
+1
+6
+3
+9
+6
+4
+9
+0
+3
+0
+5
+6
+4
+2
+9
+4
+3
+5
+8
+0
+1
+6
+4
+4
+6
+4
+1
+5
+0
+3
+0
+2
+4
+1
+7
+4
+7
+1
+7
+7
+5
+5
+3
+9
+2
+4
+9
+0
+1
+2
+0
+9
+5
+2
+6
+7
+4
+6
+3
+6
+7
+4
+0
+6
+6
+9
+3
+1
+4
+5
+0
+5
+3
+7
+9
+2
+7
+1
+4
+4
+0
+5
+3
+1
+2
+7
+4
+9
+1
+1
+2
+5
+9
+3
+2
+1
+5
+0
+6
+4
+1
+7
+1
+4
+0
+4
+0
+7
+2
+1
+6
+9
+6
+2
+9
+0
+5
+2
+5
+7
+9
+0
+4
+4
+5
+4
+2
+6
+9
+7
+5
+0
+4
+3
+6
+6
+7
+1
+5
+0
+3
+0
+4
+9
+2
+5
+7
+5
+1
+2
+3
+1
+9
+4
+2
+5
+1
+7
+5
+3
+0
+1
+0
+7
+3
+1
+1
+3
+9
+5
+0
+4
+3
+7
+7
+5
+2
+6
+6
+6
+7
+2
+9
+8
+8
+7
+4
+7
+1
+1
+9
+8
+8
+8
+2
+1
+5
+3
+9
+8
+8
+7
+7
+0
+3
+0
+9
+2
+8
+6
+5
+6
+3
+4
+7
+5
+1
+2
+5
+9
+4
+6
+3
+6
+0
+0
+0
+9
+1
+6
+1
+3
+0
+4
+0
+5
+7
+1
+9
+3
+4
+5
+4
+9
+2
+2
+3
+7
+7
+3
+4
+1
+9
+4
+2
+3
+1
+3
+7
+0
+9
+7
+3
+7
+7
+1
+8
+2
+0
+5
+3
+5
+2
+4
+6
+9
+2
+2
+0
+5
+3
+3
+1
+0
+9
+0
+6
+7
+3
+1
+0
+6
+7
+0
+4
+4
+0
+4
+6
+2
+6
+6
+7
+0
+4
+7
+2
+7
+2
+2
+4
+4
+5
+3
+9
+0
+1
+2
+3
+9
+0
+6
+7
+1
+6
+0
+7
+9
+4
+3
+6
+4
+1
+4
+3
+0
+6
+0
+5
+2
+4
+4
+6
+5
+1
+6
+5
+3
+6
+2
+4
+1
+9
+7
+1
+3
+0
+5
+1
+7
+9
+3
+9
+5
+0
+1
+5
+2
+9
+7
+7
+4
+7
+9
+0
+9
+5
+5
+3
+1
+7
+9
+7
+7
+9
+1
+3
+3
+5
+0
+0
+9
+4
+1
+4
+4
+4
+4
+6
+2
+6
+0
+3
+7
+1
+3
+8
+8
+2
+6
+5
+8
+4
+3
+9
+4
+8
+4
+2
+8
+8
+8
+8
+6
+6
+8
+8
+8
+8
+3
+8
+8
+8
+8
+8
+8
+8
+0
+8
+2
+5
+4
+6
+8
+1
+3
+7
+0
+6
+9
+4
+1
+9
+6
+8
+8
+6
+8
+3
+8
+5
+8
+8
+8
+8
+8
+3
+0
+7
+5
+6
+6
+1
+9
+5
+8
+3
+2
+0
+1
+7
+2
+1
+5
+3
+4
+1
+8
+1
+9
+2
+0
+4
+1
+7
+4
+7
+6
+6
+2
+9
+0
+0
+3
+5
+4
+7
+1
+2
+6
+6
+5
+0
+2
+4
+4
+5
+3
+2
+0
+0
+1
+9
+6
+5
+5
+1
+7
+6
+9
+9
+2
+0
+6
+3
+6
+6
+0
+5
+7
+2
+2
+3
+9
+6
+5
+9
+0
+3
+1
+2
+3
+7
+9
+9
+5
+7
+0
+5
+3
+1
+9
+9
+2
+2
+6
+9
+0
+5
+0
+7
+2
+1
+9
+9
+7
+2
+2
+5
+1
+5
+9
+4
+3
+9
+4
+7
+0
+5
+9
+2
+3
+4
+0
+0
+5
+3
+5
+9
+2
+1
+3
+4
+4
+7
+4
+9
+1
+5
+6
+6
+5
+4
+0
+1
+3
+1
+7
+2
+5
+7
+1
+2
+6
+6
+0
+1
+6
+0
+7
+9
+2
+3
+6
+0
+9
+6
+6
+1
+5
+2
+2
+5
+9
+0
+2
+7
+6
+6
+1
+2
+7
+5
+5
+0
+5
+3
+3
+7
+5
+1
+8
+8
+7
+4
+8
+8
+4
+8
+8
+8
+8
+2
+8
+3
+8
+9
+2
+0
+7
+7
+3
+2
+3
+4
+9
+6
+4
+0
+4
+7
+3
+9
+4
+1
+0
+0
+9
+9
+5
+4
+1
+5
+7
+3
+9
+9
+1
+2
+2
+4
+4
+5
+2
+7
+0
+0
+7
+6
+7
+7
+1
+2
+6
+6
+7
+5
+2
+1
+7
+9
+2
+7
+0
+6
+6
+6
+9
+1
+3
+2
+6
+1
+5
+3
+2
+7
+6
+6
+1
+2
+0
+3
+5
+9
+3
+0
+7
+7
+9
+6
+4
+3
+2
+2
+2
+1
+9
+2
+2
+3
+4
+0
+2
+4
+0
+5
+0
+3
+7
+7
+4
+2
+9
+4
+6
+6
+4
+1
+3
+5
+7
+9
+5
+4
+4
+3
+4
+0
+9
+9
+7
+7
+6
+4
+7
+0
+9
+7
+6
+5
+6
+6
+3
+2
+9
+0
+4
+0
+5
+7
+3
+2
+7
+7
+1
+3
+9
+1
+3
+0
+2
+5
+4
+6
+6
+6
+9
+0
+4
+2
+6
+6
+7
+7
+3
+9
+5
+0
+1
+5
+1
+5
+6
+6
+7
+1
+6
+6
+6
+5
+5
+9
+1
+2
+0
+1
+9
+9
+5
+7
+5
+0
+2
+4
+4
+3
+4
+9
+1
+9
+5
+2
+9
+3
+8
+8
+0
+8
+0
+8
+8
+9
+8
+3
+2
+8
+7
+6
+8
+7
+8
+8
+3
+2
+8
+8
+8
+8
+8
+8
+5
+8
+8
+7
+8
+8
+8
+0
+1
+8
+3
+6
+2
+6
+5
+7
+2
+0
+3
+0
+8
+2
+1
+3
+6
+4
+2
+5
+8
+9
+8
+3
+8
+1
+9
+2
+7
+0
+0
+3
+7
+9
+5
+2
+5
+1
+1
+3
+6
+9
+7
+0
+1
+7
+4
+6
+2
+7
+8
+0
+6
+4
+2
+4
+4
+9
+1
+5
+1
+0
+6
+4
+4
+1
+4
+7
+2
+5
+9
+7
+1
+4
+3
+4
+5
+1
+5
+1
+9
+9
+3
+4
+4
+0
+1
+0
+1
+5
+2
+6
+7
+6
+9
+2
+9
+3
+3
+7
+0
+4
+0
+5
+7
+6
+4
+0
+3
+6
+9
+6
+9
+3
+1
+6
+6
+2
+9
+7
+5
+3
+0
+5
+4
+1
+6
+4
+6
+6
+4
+7
+3
+5
+5
+9
+2
+3
+1
+3
+2
+0
+5
+9
+0
+2
+0
+4
+3
+0
+4
+9
+7
+1
+5
+2
+3
+4
+6
+6
+0
+6
+5
+4
+3
+1
+4
+2
+7
+7
+9
+3
+1
+5
+4
+5
+2
+3
+9
+7
+2
+1
+7
+7
+5
+2
+1
+5
+3
+9
+2
+4
+5
+1
+7
+9
+0
+0
+3
+1
+7
+4
+6
+9
+5
+1
+5
+1
+4
+1
+9
+3
+3
+2
+1
+6
+6
+7
+9
+9
+3
+9
+8
+8
+1
+4
+8
+8
+8
+3
+8
+8
+8
+8
+8
+8
+8
+8
+3
+5
+2
+6
+7
+9
+7
+4
+3
+4
+4
+2
+4
+5
+0
+1
+7
+8
+0
+7
+4
+2
+8
+5
+8
+0
+3
+4
+1
+4
+5
+8
+8
+8
+9
+8
+8
+8
+7
+8
+6
+6
+9
+5
+2
+8
+6
+8
+6
+4
+6
+6
+3
+9
+7
+2
+2
+3
+5
+0
+3
+9
+9
+5
+0
+0
+5
+4
+7
+4
+4
+1
+4
+3
+2
+0
+9
+9
+2
+4
+7
+3
+7
+3
+1
+9
+1
+4
+2
+4
+1
+3
+0
+1
+6
+6
+7
+2
+0
+1
+6
+6
+7
+0
+6
+5
+6
+6
+3
+9
+2
+2
+6
+5
+7
+2
+2
+9
+1
+0
+2
+1
+9
+1
+7
+5
+3
+7
+6
+2
+5
+7
+1
+4
+0
+5
+4
+1
+9
+3
+7
+7
+3
+1
+5
+0
+1
+2
+2
+1
+3
+4
+7
+4
+4
+0
+4
+0
+7
+0
+1
+4
+9
+0
+5
+3
+3
+1
+6
+5
+2
+9
+1
+3
+7
+7
+0
+0
+2
+7
+4
+3
+9
+2
+5
+9
+0
+0
+2
+7
+9
+7
+2
+9
+5
+0
+0
+5
+9
+1
+6
+6
+2
+3
+6
+7
+9
+0
+3
+8
+2
+2
+8
+8
+8
+8
+8
+8
+8
+8
+8
+1
+8
+7
+4
+6
+4
+6
+5
+2
+9
+4
+0
+4
+4
+0
+7
+1
+9
+5
+8
+5
+4
+8
+4
+8
+0
+3
+5
+1
+8
+4
+9
+4
+4
+3
+0
+8
+5
+8
+1
+5
+8
+9
+8
+7
+0
+8
+0
+6
+8
+1
+5
+8
+1
+0
+9
+7
+7
+2
+6
+3
+3
+6
+1
+2
+6
+0
+1
+6
+1
+8
+9
+7
+6
+6
+8
+0
+3
+7
+9
+4
+2
+5
+3
+1
+3
+9
+0
+0
+2
+3
+5
+6
+3
+9
+6
+5
+6
+2
+2
+4
+4
+9
+2
+5
+0
+6
+7
+0
+9
+4
+5
+9
+7
+3
+9
+3
+2
+6
+1
+4
+2
+6
+4
+3
+7
+2
+2
+1
+5
+4
+2
+0
+3
+5
+5
+2
+5
+4
+7
+3
+3
+7
+4
+1
+2
+5
+0
+5
+2
+0
+7
+0
+1
+7
+5
+9
+0
+2
+0
+6
+4
+0
+2
+3
+4
+9
+3
+7
+1
+7
+9
+2
+6
+6
+5
+6
+0
+1
+7
+7
+1
+4
+6
+1
+4
+6
+9
+0
+6
+2
+1
+7
+3
+7
+2
+9
+6
+5
+5
+2
+7
+4
+9
+9
+4
+1
+4
+0
+2
+5
+4
+1
+2
+3
+6
+7
+2
+5
+1
+4
+4
+3
+4
+5
+6
+2
+5
+0
+6
+2
+9
+7
+6
+1
+2
+2
+7
+0
+9
+2
+1
+9
+7
+0
+6
+3
+1
+9
+7
+9
+4
+5
+2
+5
+0
+1
+3
+2
+2
+7
+0
+2
+2
+9
+7
+7
+0
+2
+5
+3
+6
+9
+3
+0
+4
+8
+9
+7
+0
+8
+1
+5
+6
+1
+6
+6
+8
+7
+0
+2
+6
+8
+4
+7
+1
+8
+8
+8
+8
+8
+8
+8
+8
+2
+8
+1
+3
+0
+1
+6
+8
+1
+5
+1
+4
+5
+9
+0
+1
+0
+7
+3
+0
+8
+7
+5
+2
+8
+8
+8
+3
+2
+5
+1
+7
+7
+8
+5
+9
+2
+0
+6
+0
+7
+3
+4
+9
+4
+2
+9
+4
+3
+2
+5
+9
+5
+9
+2
+2
+3
+0
+1
+0
+2
+7
+7
+0
+6
+1
+5
+3
+2
+5
+9
+1
+5
+7
+7
+3
+9
+1
+0
+6
+1
+6
+3
+3
+7
+0
+4
+7
+4
+5
+6
+4
+9
+1
+5
+5
+1
+0
+4
+6
+6
+0
+0
+5
+6
+9
+4
+9
+1
+3
+1
+4
+7
+9
+5
+7
+5
+4
+2
+1
+3
+7
+0
+5
+0
+5
+4
+7
+2
+4
+1
+9
+3
+7
+4
+5
+1
+0
+5
+0
+3
+2
+0
+6
+6
+5
+2
+1
+9
+3
+4
+2
+1
+9
+3
+6
+6
+6
+1
+0
+2
+9
+7
+7
+8
+3
+5
+8
+8
+8
+8
+0
+8
+8
+8
+8
+8
+8
+8
+4
+7
+2
+2
+9
+9
+7
+4
+6
+4
+3
+4
+0
+9
+1
+6
+8
+4
+9
+7
+3
+2
+8
+8
+8
+3
+1
+4
+5
+1
+4
+0
+7
+3
+2
+8
+8
+8
+5
+8
+8
+5
+9
+8
+2
+8
+8
+8
+1
+2
+9
+3
+5
+9
+1
+0
+0
+0
+9
+9
+4
+9
+2
+7
+4
+0
+9
+2
+1
+8
+1
+2
+5
+1
+9
+0
+2
+0
+6
+1
+0
+4
+4
+9
+4
+5
+3
+5
+9
+6
+0
+6
+0
+6
+2
+6
+1
+6
+0
+9
+0
+4
+5
+2
+4
+7
+9
+1
+1
+2
+3
+4
+0
+1
+0
+3
+5
+4
+4
+4
+6
+6
+5
+3
+0
+6
+3
+9
+4
+5
+7
+3
+6
+6
+6
+5
+5
+4
+4
+3
+7
+7
+9
+2
+5
+6
+0
+6
+1
+3
+3
+9
+7
+2
+1
+7
+5
+1
+3
+9
+5
+0
+4
+1
+1
+4
+2
+9
+0
+5
+1
+2
+2
+1
+7
+9
+3
+0
+1
+4
+9
+4
+4
+9
+3
+1
+5
+0
+6
+0
+2
+6
+4
+5
+2
+0
+9
+6
+1
+5
+7
+4
+6
+2
+9
+3
+3
+1
+3
+6
+1
+7
+7
+9
+6
+3
+3
+0
+6
+4
+5
+9
+4
+3
+1
+6
+2
+6
+9
+7
+5
+0
+3
+5
+0
+2
+9
+3
+1
+3
+9
+1
+0
+2
+6
+6
+4
+6
+9
+2
+5
+7
+6
+5
+0
+3
+3
+6
+6
+4
+7
+3
+0
+5
+3
+4
+2
+9
+4
+3
+5
+2
+4
+8
+8
+8
+2
+7
+0
+4
+0
+8
+1
+5
+5
+1
+8
+8
+9
+8
+4
+1
+8
+8
+8
+8
+8
+6
+2
+8
+0
+8
+8
+8
+2
+3
+3
+0
+2
+0
+7
+8
+4
+1
+6
+6
+8
+5
+6
+0
+6
+9
+3
+8
+1
+8
+2
+7
+9
+9
+3
+8
+8
+8
+5
+1
+5
+9
+1
+7
+3
+1
+9
+0
+0
+2
+3
+4
+1
+7
+9
+7
+1
+7
+4
+7
+3
+1
+2
+8
+9
+5
+0
+4
+6
+0
+4
+2
+6
+3
+6
+0
+9
+0
+5
+9
+7
+5
+3
+7
+9
+2
+0
+0
+3
+2
+3
+5
+5
+4
+4
+0
+4
+7
+3
+7
+6
+6
+1
+4
+4
+5
+3
+1
+3
+7
+0
+4
+2
+6
+1
+0
+4
+1
+6
+6
+0
+2
+5
+1
+9
+5
+2
+6
+6
+3
+7
+7
+5
+4
+4
+2
+0
+6
+1
+6
+2
+9
+5
+7
+4
+1
+0
+3
+9
+2
+0
+0
+1
+7
+0
+5
+1
+9
+4
+7
+0
+1
+2
+3
+9
+9
+0
+1
+4
+8
+9
+8
+2
+3
+8
+4
+5
+0
+4
+8
+6
+2
+8
+8
+8
+8
+5
+3
+8
+6
+7
+8
+8
+8
+2
+8
+8
+8
+8
+8
+8
+9
+8
+8
+7
+8
+3
+0
+1
+9
+8
+4
+2
+6
+4
+8
+8
+8
+8
+8
+8
+7
+8
+8
+6
+8
+5
+6
+8
+5
+3
+8
+7
+7
+7
+1
+6
+3
+3
+5
+5
+9
+1
+6
+2
+1
+9
+1
+5
+9
+6
+0
+0
+2
+7
+8
+9
+9
+1
+8
+5
+3
+2
+0
+3
+4
+4
+7
+4
+3
+1
+2
+2
+5
+8
+4
+7
+7
+0
+3
+3
+2
+7
+5
+1
+4
+9
+8
+3
+9
+5
+0
+6
+7
+6
+1
+4
+0
+1
+2
+2
+1
+9
+9
+2
+4
+6
+6
+1
+0
+7
+7
+0
+2
+5
+0
+6
+5
+6
+3
+3
+7
+2
+1
+7
+4
+2
+9
+3
+0
+9
+7
+5
+9
+5
+3
+6
+6
+9
+2
+2
+0
+6
+3
+2
+4
+4
+5
+6
+9
+6
+6
+3
+2
+9
+6
+7
+5
+1
+3
+6
+6
+6
+1
+1
+0
+4
+5
+5
+7
+1
+9
+7
+1
+5
+7
+2
+2
+7
+1
+1
+2
+0
+0
+0
+2
+3
+5
+4
+7
+2
+7
+1
+3
+2
+9
+4
+7
+1
+2
+0
+7
+9
+2
+3
+4
+4
+6
+2
+3
+3
+9
+6
+6
+1
+3
+7
+3
+5
+9
+0
+5
+7
+1
+0
+8
+2
+0
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+9
+3
+0
+9
+0
+2
+6
+4
+7
+4
+4
+1
+4
+4
+0
+2
+4
+8
+8
+8
+5
+8
+6
+4
+8
+7
+2
+8
+3
+8
+7
+5
+6
+8
+0
+6
+0
+8
+8
+8
+8
+8
+8
+8
+3
+2
+8
+7
+8
+8
+5
+1
+9
+4
+2
+0
+4
+0
+1
+7
+9
+1
+3
+2
+5
+0
+8
+3
+2
+8
+8
+9
+7
+6
+1
+3
+9
+2
+6
+6
+0
+7
+2
+3
+5
+7
+1
+7
+6
+1
+6
+6
+0
+9
+3
+2
+6
+5
+4
+0
+2
+7
+3
+9
+8
+2
+7
+4
+9
+5
+4
+1
+3
+7
+0
+4
+0
+1
+2
+5
+3
+0
+5
+2
+1
+9
+0
+4
+1
+7
+1
+3
+9
+9
+0
+7
+0
+2
+4
+5
+6
+9
+3
+6
+5
+1
+6
+9
+3
+5
+3
+4
+1
+4
+0
+9
+0
+3
+7
+7
+5
+4
+9
+2
+0
+9
+3
+1
+2
+5
+9
+9
+6
+6
+3
+7
+9
+0
+9
+1
+1
+3
+2
+0
+6
+6
+1
+7
+6
+1
+6
+2
+2
+5
+9
+4
+6
+3
+4
+5
+0
+7
+1
+9
+4
+2
+3
+1
+4
+0
+8
+6
+8
+7
+1
+3
+8
+4
+2
+0
+5
+0
+8
+3
+8
+8
+4
+2
+8
+8
+8
+8
+8
+8
+8
+7
+8
+2
+8
+3
+9
+9
+3
+5
+0
+1
+7
+7
+4
+9
+5
+2
+6
+6
+0
+6
+1
+9
+8
+8
+7
+6
+8
+7
+5
+9
+3
+1
+8
+2
+8
+3
+5
+2
+0
+8
+9
+7
+8
+3
+1
+4
+3
+5
+9
+6
+0
+3
+4
+8
+8
+8
+5
+7
+0
+4
+7
+5
+6
+6
+2
+2
+1
+3
+7
+3
+4
+1
+7
+9
+0
+6
+6
+3
+1
+4
+9
+1
+2
+1
+0
+6
+3
+6
+7
+7
+4
+2
+1
+2
+0
+8
+2
+9
+5
+4
+5
+7
+5
+0
+3
+0
+1
+4
+5
+1
+9
+1
+3
+9
+2
+0
+7
+3
+3
+2
+1
+9
+7
+2
+2
+6
+3
+5
+3
+9
+6
+1
+0
+2
+4
+7
+3
+1
+0
+1
+6
+6
+6
+6
+1
+5
+6
+5
+7
+0
+9
+6
+3
+4
+4
+5
+4
+2
+9
+0
+3
+0
+7
+4
+2
+9
+5
+4
+3
+4
+7
+4
+4
+6
+1
+6
+5
+0
+6
+6
+4
+0
+2
+9
+5
+6
+6
+7
+9
+9
+4
+2
+4
+7
+1
+5
+2
+5
+6
+1
+1
+2
+3
+6
+9
+9
+1
+4
+0
+1
+3
+1
+7
+7
+5
+3
+0
+4
+9
+5
+1
+9
+1
+2
+2
+6
+9
+4
+8
+8
+5
+3
+8
+8
+8
+8
+8
+8
+8
+8
+7
+8
+6
+9
+4
+0
+7
+3
+5
+6
+9
+4
+6
+4
+4
+2
+4
+7
+9
+1
+6
+0
+1
+8
+4
+2
+6
+9
+7
+7
+5
+0
+9
+4
+4
+3
+3
+8
+2
+8
+8
+0
+8
+9
+3
+8
+8
+1
+2
+8
+5
+0
+3
+0
+7
+4
+2
+3
+5
+6
+3
+2
+9
+5
+7
+3
+7
+4
+8
+8
+9
+7
+5
+0
+2
+1
+8
+8
+9
+8
+7
+7
+1
+0
+2
+5
+0
+1
+2
+2
+1
+3
+5
+7
+1
+9
+8
+1
+7
+3
+3
+4
+5
+9
+4
+5
+2
+5
+1
+6
+1
+9
+6
+4
+4
+3
+9
+0
+3
+4
+7
+6
+1
+3
+9
+1
+6
+7
+5
+0
+6
+4
+0
+6
+6
+6
+1
+0
+2
+3
+9
+4
+3
+9
+0
+9
+0
+2
+2
+5
+1
+0
+7
+7
+7
+7
+9
+9
+5
+4
+3
+5
+4
+0
+1
+4
+4
+9
+7
+7
+2
+0
+9
+3
+7
+1
+6
+6
+5
+6
+6
+6
+2
+3
+0
+7
+6
+2
+1
+0
+7
+7
+2
+4
+0
+5
+6
+5
+9
+9
+3
+2
+0
+1
+5
+3
+9
+3
+3
+5
+1
+4
+9
+8
+5
+9
+8
+5
+8
+8
+8
+8
+8
+8
+2
+3
+8
+8
+9
+2
+9
+1
+7
+2
+5
+4
+9
+6
+6
+6
+5
+1
+3
+0
+8
+9
+4
+0
+4
+0
+1
+6
+3
+1
+8
+4
+2
+3
+4
+0
+8
+5
+8
+8
+8
+2
+8
+7
+5
+0
+8
+8
+8
+3
+2
+4
+3
+9
+1
+7
+2
+1
+0
+2
+0
+9
+4
+0
+1
+7
+9
+3
+1
+7
+1
+7
+8
+1
+8
+8
+3
+6
+0
+1
+0
+7
+2
+6
+3
+1
+2
+5
+9
+3
+2
+7
+0
+5
+1
+2
+9
+9
+4
+5
+2
+4
+4
+8
+4
+3
+7
+1
+3
+2
+0
+8
+6
+6
+1
+6
+7
+5
+5
+4
+1
+4
+4
+3
+4
+6
+4
+6
+5
+9
+6
+1
+2
+6
+0
+1
+0
+9
+5
+3
+3
+5
+1
+5
+4
+9
+0
+3
+6
+3
+7
+5
+5
+9
+6
+0
+0
+1
+9
+2
+7
+4
+4
+5
+2
+0
+3
+7
+9
+9
+1
+3
+5
+2
+9
+0
+7
+6
+2
+7
+0
+3
+1
+4
+3
+5
+7
+2
+7
+7
+0
+9
+1
+6
+7
+6
+2
+3
+9
+0
+6
+0
+5
+4
+6
+4
+4
+1
+3
+9
+7
+7
+4
+1
+7
+5
+5
+0
+9
+4
+1
+4
+4
+2
+3
+7
+9
+2
+7
+3
+3
+0
+2
+6
+4
+5
+6
+3
+6
+6
+7
+2
+1
+7
+5
+9
+0
+4
+0
+5
+6
+6
+4
+7
+2
+3
+5
+5
+7
+7
+2
+3
+6
+1
+3
+2
+9
+4
+0
+5
+1
+5
+7
+2
+9
+7
+8
+8
+8
+8
+8
+8
+3
+9
+7
+1
+5
+0
+8
+0
+3
+2
+2
+8
+4
+3
+8
+8
+8
+5
+6
+8
+8
+8
+8
+2
+4
+9
+8
+8
+1
+0
+9
+1
+2
+9
+4
+6
+6
+6
+5
+3
+0
+2
+1
+8
+6
+6
+2
+7
+5
+0
+8
+5
+7
+7
+9
+3
+3
+9
+4
+1
+9
+9
+0
+9
+3
+4
+1
+7
+6
+9
+4
+3
+2
+5
+6
+6
+9
+3
+6
+8
+3
+0
+2
+0
+9
+3
+8
+2
+5
+8
+5
+2
+4
+9
+1
+7
+0
+7
+9
+1
+7
+5
+5
+3
+2
+1
+0
+8
+9
+9
+2
+4
+4
+7
+7
+5
+1
+7
+6
+6
+3
+4
+9
+2
+1
+5
+7
+0
+7
+3
+9
+1
+5
+1
+4
+5
+6
+3
+9
+4
+0
+2
+0
+7
+1
+6
+9
+1
+6
+9
+1
+2
+5
+6
+5
+7
+1
+6
+6
+1
+6
+0
+9
+0
+2
+2
+1
+7
+1
+2
+1
+0
+1
+4
+2
+1
+4
+3
+2
+9
+3
+1
+1
+0
+1
+3
+6
+8
+0
+0
+8
+8
+8
+8
+8
+5
+8
+8
+8
+8
+7
+9
+4
+1
+2
+5
+5
+3
+9
+4
+3
+0
+4
+7
+2
+3
+1
+7
+8
+4
+3
+8
+4
+8
+8
+9
+5
+8
+3
+4
+9
+6
+4
+1
+8
+0
+8
+8
+8
+5
+8
+9
+7
+8
+6
+0
+5
+1
+8
+9
+0
+3
+3
+0
+7
+7
+1
+6
+6
+1
+0
+5
+0
+8
+2
+0
+8
+8
+3
+5
+9
+7
+1
+2
+2
+3
+7
+8
+9
+2
+0
+1
+7
+4
+4
+7
+3
+9
+7
+0
+5
+0
+2
+3
+1
+9
+2
+2
+1
+3
+5
+4
+3
+5
+0
+2
+6
+6
+3
+1
+3
+9
+6
+4
+9
+1
+6
+4
+3
+4
+4
+0
+4
+2
+1
+9
+3
+1
+2
+4
+4
+3
+2
+5
+5
+7
+2
+1
+9
+3
+5
+7
+3
+5
+6
+6
+2
+0
+4
+3
+1
+2
+7
+5
+6
+9
+0
+6
+0
+4
+4
+1
+6
+6
+2
+0
+7
+0
+6
+7
+9
+3
+1
+3
+5
+1
+0
+0
+2
+9
+6
+4
+0
+2
+1
+0
+9
+1
+4
+1
+7
+3
+0
+7
+4
+9
+2
+5
+5
+1
+3
+4
+0
+4
+5
+2
+4
+6
+3
+5
+9
+4
+7
+5
+4
+1
+9
+1
+3
+6
+5
+4
+1
+4
+6
+6
+1
+9
+2
+7
+6
+3
+9
+6
+4
+9
+0
+2
+0
+7
+9
+4
+7
+7
+7
+7
+5
+3
+5
+9
+1
+5
+1
+0
+6
+2
+3
+6
+0
+7
+2
+5
+9
+9
+7
+1
+6
+6
+0
+6
+9
+3
+1
+2
+4
+6
+9
+0
+2
+0
+6
+5
+3
+8
+9
+8
+7
+7
+5
+0
+7
+8
+4
+7
+8
+8
+8
+8
+3
+8
+8
+5
+8
+4
+4
+8
+2
+8
+9
+4
+2
+4
+1
+3
+4
+1
+9
+1
+8
+8
+7
+7
+8
+0
+9
+5
+8
+8
+2
+3
+6
+6
+9
+6
+7
+5
+6
+2
+0
+5
+1
+9
+6
+1
+8
+5
+7
+3
+0
+9
+0
+4
+1
+0
+1
+4
+3
+9
+4
+5
+2
+3
+7
+7
+3
+1
+5
+9
+0
+2
+0
+1
+4
+2
+5
+0
+9
+3
+2
+5
+6
+6
+6
+2
+9
+5
+6
+5
+7
+6
+0
+4
+9
+1
+4
+9
+5
+8
+7
+7
+2
+4
+4
+3
+5
+2
+1
+7
+9
+9
+2
+7
+4
+7
+3
+2
+5
+9
+5
+2
+3
+1
+4
+5
+9
+3
+7
+3
+1
+5
+6
+6
+7
+9
+1
+3
+1
+2
+9
+7
+1
+9
+2
+1
+7
+3
+9
+2
+6
+6
+1
+2
+0
+4
+3
+4
+4
+6
+7
+1
+2
+7
+3
+5
+0
+0
+4
+6
+6
+2
+7
+1
+3
+4
+5
+4
+4
+3
+1
+2
+5
+9
+1
+4
+1
+3
+9
+7
+0
+7
+0
+3
+2
+1
+9
+4
+4
+2
+5
+4
+7
+6
+4
+5
+8
+2
+1
+8
+9
+4
+2
+4
+4
+7
+8
+8
+9
+7
+3
+2
+8
+1
+8
+5
+9
+8
+3
+7
+1
+8
+4
+8
+0
+9
+0
+9
+1
+2
+2
+7
+5
+9
+6
+6
+7
+6
+8
+2
+9
+3
+3
+6
+0
+5
+0
+7
+6
+3
+3
+1
+2
+7
+1
+4
+4
+9
+6
+3
+1
+6
+9
+1
+7
+7
+5
+0
+3
+4
+6
+2
+6
+9
+1
+4
+3
+8
+7
+5
+2
+9
+5
+3
+2
+1
+3
+7
+1
+5
+7
+7
+7
+4
+2
+4
+5
+9
+1
+2
+0
+5
+9
+2
+1
+9
+7
+7
+0
+0
+3
+0
+7
+1
+1
+3
+2
+6
+5
+1
+2
+1
+0
+3
+9
+9
+3
+0
+7
+5
+5
+4
+0
+9
+2
+1
+5
+3
+5
+3
+3
+0
+7
+2
+7
+7
+6
+3
+6
+9
+3
+0
+2
+4
+9
+7
+4
+3
+0
+6
+6
+2
+9
+5
+6
+3
+2
+6
+0
+1
+9
+2
+6
+5
+3
+4
+4
+7
+9
+1
+5
+9
+5
+4
+3
+0
+4
+9
+1
+7
+2
+1
+3
+4
+2
+9
+4
+0
+3
+2
+0
+4
+7
+2
+5
+3
+4
+5
+2
+5
+6
+6
+2
+1
+7
+8
+2
+5
+8
+8
+8
+8
+8
+0
+8
+8
+8
+5
+8
+8
+1
+7
+3
+7
+6
+2
+7
+4
+5
+3
+4
+1
+1
+0
+2
+3
+4
+8
+8
+8
+7
+8
+8
+8
+1
+3
+8
+5
+6
+8
+6
+6
+9
+8
+3
+9
+8
+8
+8
+8
+8
+8
+8
+8
+8
+0
+8
+5
+0
+5
+8
+4
+3
+4
+2
+6
+4
+9
+0
+2
+0
+5
+8
+2
+8
+9
+5
+1
+2
+8
+7
+5
+9
+9
+1
+8
+4
+1
+5
+8
+5
+9
+7
+3
+3
+5
+1
+0
+9
+1
+8
+5
+7
+6
+9
+2
+7
+4
+4
+7
+4
+2
+0
+8
+0
+2
+8
+4
+3
+7
+9
+1
+0
+0
+1
+4
+6
+4
+2
+6
+4
+7
+5
+0
+1
+3
+7
+7
+1
+9
+6
+6
+3
+0
+3
+5
+5
+2
+4
+1
+7
+5
+3
+0
+4
+2
+7
+7
+9
+6
+3
+4
+1
+4
+9
+0
+4
+0
+3
+2
+7
+7
+7
+6
+5
+0
+6
+1
+2
+5
+6
+3
+3
+9
+1
+0
+6
+5
+9
+6
+0
+3
+3
+0
+5
+7
+2
+2
+9
+3
+0
+7
+2
+0
+9
+4
+2
+4
+4
+5
+2
+2
+9
+3
+6
+3
+3
+6
+3
+0
+9
+9
+7
+3
+1
+4
+0
+1
+4
+9
+4
+0
+6
+2
+0
+6
+9
+2
+5
+3
+6
+6
+3
+7
+0
+9
+0
+2
+7
+1
+9
+5
+6
+6
+7
+1
+2
+3
+9
+0
+2
+9
+1
+5
+1
+0
+1
+5
+5
+2
+2
+1
+0
+3
+7
+0
+7
+1
+1
+2
+5
+3
+3
+1
+6
+6
+6
+3
+6
+5
+3
+9
+4
+0
+4
+0
+9
+2
+0
+9
+8
+0
+8
+3
+7
+2
+2
+9
+8
+5
+2
+3
+1
+0
+3
+4
+7
+0
+1
+0
+9
+3
+3
+5
+2
+5
+7
+1
+2
+0
+3
+9
+7
+7
+2
+6
+9
+3
+4
+0
+5
+6
+7
+5
+9
+3
+4
+6
+3
+5
+6
+6
+1
+9
+0
+3
+4
+1
+4
+0
+5
+9
+5
+9
+3
+2
+1
+5
+9
+3
+2
+1
+3
+4
+5
+2
+7
+1
+0
+2
+1
+0
+9
+1
+5
+9
+4
+5
+0
+7
+9
+6
+1
+9
+1
+3
+0
+4
+0
+4
+4
+9
+4
+3
+5
+6
+1
+5
+0
+9
+2
+3
+5
+4
+0
+2
+4
+5
+1
+3
+9
+9
+4
+1
+7
+7
+5
+1
+0
+2
+0
+9
+0
+1
+1
+3
+4
+2
+7
+6
+0
+7
+5
+4
+4
+9
+5
+6
+5
+0
+7
+0
+6
+6
+3
+4
+4
+1
+6
+5
+2
+6
+3
+4
+6
+2
+7
+7
+1
+2
+3
+0
+6
+4
+9
+8
+6
+3
+8
+8
+8
+8
+8
+1
+8
+8
+8
+8
+3
+8
+9
+3
+2
+3
+1
+0
+1
+4
+9
+1
+4
+7
+6
+6
+0
+1
+8
+9
+1
+8
+5
+2
+7
+7
+6
+9
+8
+4
+1
+4
+0
+6
+1
+5
+8
+8
+7
+8
+6
+6
+0
+8
+8
+1
+2
+5
+3
+8
+2
+1
+0
+4
+2
+5
+3
+9
+1
+2
+7
+3
+9
+6
+0
+6
+8
+8
+8
+3
+6
+6
+5
+6
+7
+8
+6
+7
+9
+8
+3
+2
+6
+6
+4
+8
+7
+3
+6
+7
+3
+2
+0
+0
+9
+9
+4
+5
+8
+4
+4
+1
+4
+7
+2
+7
+5
+8
+1
+4
+9
+3
+3
+2
+2
+7
+5
+0
+0
+0
+1
+3
+4
+1
+4
+1
+6
+6
+5
+4
+3
+7
+2
+7
+1
+9
+2
+0
+3
+0
+6
+6
+4
+9
+6
+1
+2
+4
+3
+1
+5
+1
+0
+6
+0
+2
+3
+4
+1
+7
+4
+5
+7
+5
+6
+7
+9
+9
+6
+3
+5
+7
+9
+1
+0
+5
+1
+3
+9
+9
+5
+2
+6
+6
+7
+3
+2
+9
+6
+6
+5
+2
+5
+3
+6
+2
+6
+4
+6
+4
+4
+3
+4
+5
+0
+5
+0
+3
+1
+3
+4
+9
+3
+2
+2
+0
+9
+4
+9
+3
+4
+4
+4
+2
+9
+5
+7
+7
+3
+1
+0
+3
+2
+3
+5
+9
+3
+4
+6
+4
+4
+6
+1
+3
+5
+4
+3
+5
+1
+0
+6
+0
+3
+6
+3
+2
+9
+7
+5
+6
+7
+9
+1
+6
+5
+6
+9
+3
+2
+0
+7
+7
+9
+1
+4
+8
+1
+5
+2
+1
+8
+9
+7
+7
+8
+3
+1
+2
+8
+5
+1
+8
+4
+0
+8
+8
+8
+8
+8
+8
+2
+8
+8
+6
+8
+9
+4
+5
+9
+0
+7
+1
+2
+5
+6
+3
+2
+7
+1
+9
+5
+2
+5
+6
+3
+0
+2
+1
+6
+3
+7
+2
+9
+5
+5
+2
+0
+3
+6
+1
+0
+9
+3
+4
+2
+7
+1
+5
+9
+9
+3
+1
+0
+2
+2
+3
+9
+4
+2
+7
+4
+1
+0
+3
+5
+0
+6
+2
+1
+6
+4
+7
+2
+3
+1
+9
+7
+4
+9
+6
+4
+3
+3
+0
+5
+2
+5
+4
+4
+1
+2
+0
+6
+7
+6
+2
+1
+9
+5
+1
+4
+0
+8
+8
+6
+8
+8
+0
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+9
+2
+7
+3
+5
+2
+1
+0
+9
+0
+5
+3
+4
+5
+3
+5
+6
+2
+5
+8
+8
+1
+7
+8
+8
+8
+8
+8
+1
+8
+2
+9
+8
+8
+1
+8
+7
+8
+8
+8
+8
+0
+8
+8
+8
+8
+8
+8
+7
+2
+4
+7
+4
+3
+0
+9
+1
+5
+2
+4
+6
+6
+3
+2
+7
+5
+8
+2
+9
+4
+3
+1
+2
+6
+6
+6
+9
+5
+1
+4
+3
+5
+0
+0
+1
+9
+6
+6
+3
+4
+2
+6
+7
+9
+5
+1
+5
+6
+0
+1
+0
+3
+3
+0
+2
+0
+1
+5
+7
+7
+4
+7
+1
+0
+1
+6
+5
+9
+2
+0
+7
+0
+2
+1
+9
+9
+1
+3
+3
+5
+1
+2
+2
+4
+4
+3
+4
+6
+5
+0
+6
+0
+7
+7
+9
+2
+7
+4
+6
+1
+4
+3
+9
+0
+2
+9
+1
+7
+5
+3
+3
+0
+2
+7
+2
+1
+5
+4
+9
+4
+4
+2
+4
+0
+6
+6
+0
+1
+3
+1
+5
+2
+5
+3
+1
+9
+3
+6
+0
+4
+7
+5
+9
+9
+2
+2
+0
+6
+6
+1
+5
+9
+5
+9
+2
+5
+1
+7
+6
+3
+0
+6
+0
+7
+9
+5
+7
+3
+7
+7
+4
+5
+9
+1
+4
+9
+3
+1
+1
+5
+0
+4
+0
+3
+4
+5
+4
+6
+9
+1
+1
+2
+4
+0
+5
+7
+9
+7
+9
+6
+2
+0
+3
+4
+2
+5
+1
+5
+3
+0
+3
+6
+9
+6
+5
+1
+7
+6
+3
+5
+9
+0
+8
+8
+5
+4
+8
+8
+8
+8
+8
+8
+9
+8
+1
+0
+8
+6
+5
+3
+1
+0
+9
+6
+2
+4
+7
+5
+6
+6
+1
+9
+7
+2
+2
+6
+9
+3
+0
+7
+6
+6
+1
+2
+7
+3
+8
+1
+0
+5
+8
+4
+9
+8
+4
+8
+2
+0
+5
+8
+9
+4
+8
+8
+4
+8
+2
+7
+5
+9
+1
+5
+0
+7
+0
+1
+9
+9
+8
+0
+3
+4
+0
+8
+2
+1
+7
+7
+5
+7
+6
+6
+1
+9
+0
+1
+3
+6
+9
+7
+7
+5
+6
+6
+3
+1
+9
+5
+6
+1
+1
+3
+2
+5
+6
+4
+0
+6
+6
+3
+7
+0
+5
+1
+5
+2
+2
+3
+3
+4
+2
+5
+1
+3
+6
+1
+3
+1
+7
+7
+6
+0
+1
+2
+9
+4
+0
+9
+6
+4
+3
+1
+4
+5
+9
+9
+0
+3
+0
+5
+3
+7
+4
+1
+6
+0
+2
+0
+9
+4
+1
+4
+4
+7
+5
+3
+9
+0
+9
+9
+4
+3
+5
+3
+9
+1
+7
+0
+7
+7
+6
+3
+1
+6
+8
+8
+7
+8
+8
+8
+8
+8
+8
+8
+8
+6
+8
+8
+8
+3
+3
+0
+5
+1
+7
+7
+2
+5
+3
+4
+1
+2
+0
+1
+5
+2
+0
+7
+6
+6
+9
+8
+7
+9
+8
+2
+0
+5
+0
+8
+8
+9
+8
+8
+8
+8
+5
+8
+2
+7
+8
+1
+8
+4
+8
+6
+4
+3
+0
+4
+1
+6
+4
+1
+6
+3
+5
+8
+0
+4
+1
+2
+1
+3
+3
+2
+0
+8
+0
+5
+8
+8
+4
+8
+7
+8
+1
+8
+0
+3
+5
+1
+3
+2
+2
+5
+7
+0
+2
+3
+3
+5
+6
+6
+5
+3
+3
+2
+9
+9
+7
+6
+7
+1
+6
+6
+3
+9
+0
+0
+1
+5
+7
+0
+4
+2
+3
+6
+6
+6
+5
+3
+0
+9
+3
+2
+7
+1
+9
+3
+5
+0
+1
+5
+4
+5
+9
+3
+2
+9
+7
+1
+5
+0
+1
+9
+0
+3
+0
+5
+0
+4
+9
+9
+4
+3
+7
+2
+0
+7
+9
+3
+7
+7
+5
+1
+1
+2
+6
+6
+2
+4
+7
+7
+6
+5
+7
+7
+1
+7
+9
+1
+9
+2
+5
+0
+5
+4
+1
+4
+0
+9
+7
+7
+1
+7
+3
+2
+7
+9
+0
+3
+2
+0
+9
+6
+6
+6
+5
+1
+7
+3
+9
+5
+5
+2
+1
+6
+6
+6
+2
+7
+3
+7
+0
+6
+7
+3
+9
+2
+6
+1
+1
+4
+4
+3
+4
+7
+1
+5
+6
+5
+6
+0
+1
+3
+3
+2
+5
+7
+5
+4
+9
+4
+7
+0
+6
+2
+5
+1
+9
+9
+3
+0
+4
+0
+1
+3
+5
+6
+2
+7
+3
+8
+9
+8
+8
+8
+5
+8
+7
+6
+9
+7
+8
+8
+6
+8
+8
+8
+4
+8
+8
+8
+8
+4
+8
+7
+9
+8
+8
+8
+2
+8
+8
+9
+8
+8
+8
+1
+2
+5
+0
+9
+8
+2
+1
+6
+6
+7
+5
+8
+7
+8
+6
+3
+8
+8
+8
+9
+8
+4
+7
+4
+4
+8
+0
+6
+2
+4
+6
+4
+9
+6
+1
+5
+1
+2
+2
+1
+9
+3
+3
+9
+0
+5
+0
+2
+8
+1
+3
+2
+5
+7
+4
+3
+7
+5
+3
+5
+3
+2
+1
+7
+9
+5
+5
+0
+7
+2
+2
+6
+9
+1
+2
+4
+4
+1
+1
+5
+9
+3
+6
+6
+1
+6
+5
+1
+9
+3
+1
+3
+2
+4
+6
+4
+4
+6
+4
+5
+0
+1
+2
+2
+9
+9
+6
+6
+6
+0
+7
+7
+1
+9
+3
+3
+5
+1
+4
+4
+2
+9
+4
+1
+1
+2
+6
+1
+2
+0
+0
+4
+3
+6
+1
+9
+7
+2
+6
+0
+6
+7
+2
+1
+6
+3
+5
+2
+5
+1
+7
+9
+4
+3
+8
+8
+5
+8
+8
+5
+8
+8
+8
+8
+9
+8
+8
+8
+8
+2
+2
+1
+3
+1
+0
+9
+5
+1
+1
+2
+3
+5
+6
+9
+6
+7
+4
+8
+0
+8
+3
+7
+2
+8
+6
+6
+7
+7
+3
+8
+6
+5
+6
+6
+9
+8
+4
+8
+0
+8
+5
+2
+9
+4
+3
+4
+4
+8
+1
+0
+5
+9
+7
+4
+4
+7
+4
+8
+9
+0
+2
+0
+3
+4
+2
+8
+9
+0
+7
+7
+1
+7
+8
+2
+9
+9
+4
+6
+2
+0
+6
+0
+6
+3
+5
+1
+9
+1
+7
+4
+2
+0
+1
+0
+9
+5
+9
+9
+1
+2
+3
+0
+9
+8
+2
+7
+7
+1
+3
+2
+9
+0
+7
+1
+4
+3
+7
+7
+3
+9
+1
+0
+2
+3
+5
+6
+3
+6
+5
+1
+5
+2
+2
+6
+5
+1
+4
+5
+7
+3
+3
+2
+3
+4
+4
+6
+2
+5
+1
+3
+0
+6
+0
+4
+2
+0
+9
+3
+3
+5
+0
+5
+6
+2
+7
+3
+3
+9
+5
+2
+0
+4
+0
+3
+3
+9
+7
+5
+5
+7
+9
+5
+2
+5
+3
+7
+5
+1
+9
+7
+5
+3
+3
+7
+7
+4
+9
+4
+4
+0
+6
+6
+4
+6
+9
+2
+6
+9
+3
+2
+1
+4
+5
+1
+7
+7
+3
+4
+5
+9
+1
+3
+2
+0
+4
+5
+1
+9
+7
+7
+3
+5
+5
+6
+4
+1
+4
+3
+6
+6
+5
+7
+4
+7
+4
+5
+0
+3
+9
+6
+6
+6
+5
+4
+2
+3
+6
+0
+9
+6
+6
+4
+7
+1
+9
+5
+0
+0
+2
+0
+1
+3
+0
+2
+7
+8
+8
+8
+8
+8
+8
+9
+5
+8
+0
+7
+2
+1
+8
+8
+0
+8
+8
+8
+8
+2
+8
+8
+3
+8
+6
+8
+8
+8
+1
+2
+4
+8
+4
+5
+8
+0
+6
+6
+2
+4
+5
+6
+4
+6
+8
+3
+8
+2
+6
+4
+0
+6
+2
+5
+8
+8
+8
+0
+7
+7
+2
+3
+1
+7
+9
+1
+4
+0
+4
+3
+5
+8
+1
+5
+6
+4
+7
+0
+3
+7
+6
+6
+8
+5
+5
+4
+3
+2
+9
+0
+5
+9
+2
+0
+5
+1
+3
+9
+6
+6
+1
+7
+0
+5
+5
+9
+7
+7
+6
+4
+7
+0
+3
+9
+5
+1
+1
+5
+3
+2
+3
+9
+1
+0
+1
+2
+9
+4
+1
+4
+4
+0
+4
+1
+9
+3
+3
+5
+3
+1
+4
+5
+2
+3
+3
+9
+0
+5
+6
+7
+6
+2
+4
+1
+5
+1
+5
+2
+9
+3
+6
+3
+0
+6
+6
+6
+7
+1
+5
+3
+2
+2
+0
+6
+2
+6
+7
+7
+3
+2
+2
+5
+0
+7
+0
+9
+3
+0
+8
+8
+1
+8
+8
+8
+8
+6
+8
+5
+8
+8
+1
+8
+0
+8
+1
+7
+6
+5
+3
+1
+2
+2
+9
+4
+4
+1
+1
+0
+1
+2
+4
+9
+8
+8
+8
+8
+3
+8
+1
+2
+8
+0
+7
+3
+3
+7
+8
+8
+8
+7
+8
+5
+3
+1
+8
+6
+8
+4
+5
+4
+6
+6
+3
+9
+0
+0
+1
+0
+9
+8
+3
+2
+6
+6
+5
+3
+9
+4
+6
+6
+2
+5
+5
+3
+2
+0
+0
+0
+1
+2
+4
+1
+7
+7
+2
+5
+6
+6
+7
+2
+0
+3
+5
+9
+7
+7
+1
+5
+9
+9
+3
+4
+4
+0
+4
+5
+9
+2
+7
+1
+0
+4
+6
+6
+9
+3
+3
+4
+1
+2
+2
+1
+0
+1
+0
+5
+7
+5
+1
+2
+7
+3
+1
+8
+1
+5
+9
+9
+4
+1
+3
+7
+5
+1
+7
+5
+7
+4
+4
+1
+9
+0
+2
+0
+7
+5
+7
+4
+3
+7
+4
+2
+6
+6
+5
+1
+9
+1
+0
+6
+2
+1
+7
+7
+9
+6
+5
+4
+0
+3
+2
+3
+3
+9
+2
+7
+5
+0
+0
+5
+9
+9
+5
+2
+2
+1
+0
+0
+3
+4
+5
+4
+4
+3
+3
+5
+2
+0
+0
+0
+0
+2
+4
+7
+9
+9
+2
+2
+7
+4
+9
+4
+4
+9
+4
+6
+2
+0
+1
+3
+5
+0
+7
+5
+2
+7
+6
+1
+9
+6
+3
+4
+4
+2
+0
+3
+1
+2
+5
+1
+9
+2
+2
+5
+7
+4
+3
+4
+4
+9
+1
+3
+3
+5
+0
+1
+9
+3
+6
+6
+5
+1
+1
+5
+2
+6
+8
+1
+0
+8
+0
+6
+8
+7
+1
+8
+6
+3
+8
+8
+5
+9
+8
+8
+5
+8
+8
+7
+8
+8
+8
+8
+4
+5
+8
+8
+2
+8
+7
+7
+4
+2
+4
+8
+3
+9
+2
+5
+8
+4
+9
+0
+4
+1
+8
+2
+8
+3
+9
+0
+7
+9
+4
+8
+5
+3
+9
+5
+2
+6
+1
+5
+7
+0
+9
+9
+3
+5
+2
+6
+4
+1
+7
+7
+6
+7
+5
+6
+7
+7
+9
+3
+6
+0
+0
+0
+2
+1
+5
+3
+3
+2
+9
+7
+1
+9
+5
+3
+7
+1
+9
+6
+9
+2
+1
+3
+6
+5
+2
+4
+4
+9
+4
+6
+3
+0
+0
+0
+5
+1
+1
+5
+3
+5
+3
+1
+5
+6
+6
+4
+0
+5
+4
+4
+1
+2
+2
+7
+5
+4
+7
+1
+7
+7
+0
+2
+3
+1
+9
+4
+0
+5
+0
+3
+1
+0
+3
+9
+2
+0
+5
+0
+5
+3
+2
+9
+7
+4
+6
+6
+7
+7
+3
+5
+7
+1
+1
+2
+4
+0
+6
+9
+6
+6
+7
+5
+2
+3
+1
+9
+3
+4
+6
+6
+6
+0
+7
+0
+3
+1
+2
+2
+5
+3
+5
+0
+6
+6
+6
+2
+1
+4
+7
+4
+3
+5
+4
+0
+9
+3
+8
+2
+8
+8
+3
+8
+0
+8
+6
+9
+8
+8
+3
+5
+7
+7
+8
+8
+7
+2
+8
+8
+8
+8
+8
+8
+8
+8
+3
+8
+8
+8
+5
+1
+4
+3
+3
+0
+2
+8
+1
+9
+2
+5
+5
+1
+0
+0
+8
+9
+8
+2
+5
+4
+4
+0
+2
+9
+8
+3
+3
+2
+7
+4
+4
+5
+2
+5
+1
+7
+9
+4
+0
+4
+7
+3
+4
+3
+6
+1
+0
+0
+5
+1
+6
+6
+9
+5
+6
+9
+1
+0
+0
+0
+9
+1
+6
+6
+1
+0
+6
+3
+6
+9
+3
+9
+2
+5
+0
+3
+9
+9
+1
+9
+0
+2
+5
+4
+4
+7
+4
+1
+4
+1
+4
+2
+0
+8
+0
+5
+9
+4
+6
+2
+4
+6
+5
+4
+9
+7
+0
+3
+2
+0
+4
+6
+2
+6
+0
+5
+3
+4
+7
+4
+4
+7
+4
+3
+0
+9
+3
+1
+9
+1
+7
+3
+7
+7
+1
+0
+9
+5
+5
+4
+2
+3
+0
+1
+9
+2
+5
+7
+0
+2
+6
+6
+9
+0
+2
+0
+6
+5
+7
+0
+9
+9
+1
+6
+1
+3
+5
+1
+3
+0
+0
+0
+2
+1
+4
+6
+5
+9
+1
+5
+7
+7
+2
+1
+4
+9
+2
+1
+5
+0
+9
+3
+7
+7
+4
+1
+2
+3
+9
+3
+2
+4
+7
+4
+2
+7
+7
+0
+3
+9
+5
+4
+1
+2
+9
+1
+3
+9
+6
+6
+7
+6
+8
+8
+3
+6
+8
+8
+8
+8
+8
+2
+8
+8
+8
+8
+8
+8
+3
+7
+1
+7
+7
+5
+2
+7
+0
+4
+3
+2
+5
+6
+9
+9
+7
+1
+8
+7
+9
+2
+5
+9
+1
+6
+1
+0
+3
+0
+6
+6
+0
+3
+4
+5
+4
+8
+8
+6
+8
+3
+0
+4
+0
+8
+8
+5
+2
+6
+0
+6
+1
+4
+4
+6
+4
+1
+5
+3
+7
+5
+7
+4
+4
+3
+7
+1
+9
+5
+8
+0
+8
+0
+1
+2
+5
+1
+5
+1
+1
+2
+1
+3
+9
+9
+5
+9
+7
+7
+7
+1
+6
+6
+3
+9
+0
+0
+2
+5
+5
+9
+1
+2
+6
+1
+6
+0
+2
+9
+7
+7
+9
+5
+7
+3
+2
+4
+0
+5
+9
+2
+5
+3
+7
+7
+1
+7
+9
+0
+1
+4
+3
+4
+4
+1
+9
+6
+2
+6
+5
+7
+6
+2
+0
+1
+0
+1
+6
+6
+5
+4
+1
+4
+0
+6
+0
+3
+7
+0
+9
+1
+6
+6
+0
+6
+3
+0
+9
+7
+5
+4
+2
+4
+0
+7
+2
+9
+6
+4
+2
+3
+1
+5
+3
+0
+7
+7
+4
+3
+9
+1
+9
+9
+5
+1
+1
+3
+2
+5
+7
+7
+1
+0
+5
+1
+6
+2
+4
+0
+1
+0
+7
+7
+5
+3
+6
+5
+0
+6
+0
+4
+9
+3
+6
+6
+4
+5
+4
+0
+9
+6
+3
+1
+5
+4
+2
+4
+9
+3
+8
+4
+4
+7
+4
+3
+0
+0
+2
+0
+8
+6
+9
+7
+1
+5
+7
+2
+1
+7
+9
+3
+6
+6
+5
+8
+2
+0
+9
+0
+8
+4
+0
+1
+5
+2
+2
+5
+6
+3
+1
+4
+0
+7
+4
+9
+7
+7
+3
+1
+7
+0
+9
+3
+5
+9
+3
+7
+2
+5
+7
+6
+1
+7
+2
+2
+3
+4
+0
+9
+1
+3
+7
+0
+3
+7
+6
+2
+0
+5
+3
+5
+2
+1
+6
+4
+4
+6
+4
+7
+2
+6
+9
+1
+7
+2
+6
+6
+5
+0
+2
+7
+6
+4
+5
+4
+7
+0
+3
+2
+5
+3
+5
+4
+9
+0
+4
+0
+1
+3
+3
+3
+2
+7
+5
+4
+4
+2
+9
+3
+3
+5
+4
+6
+6
+2
+7
+3
+3
+0
+2
+0
+4
+5
+9
+9
+3
+0
+0
+2
+4
+3
+5
+9
+3
+7
+1
+5
+7
+7
+9
+1
+5
+1
+3
+5
+9
+2
+1
+9
+7
+7
+5
+1
+9
+1
+4
+3
+3
+1
+7
+7
+5
+0
+7
+4
+4
+7
+3
+6
+1
+6
+7
+4
+4
+5
+6
+6
+0
+7
+0
+1
+6
+4
+3
+4
+4
+9
+6
+2
+6
+1
+3
+7
+9
+7
+5
+9
+1
+3
+0
+1
+2
+4
+8
+7
+8
+8
+8
+5
+8
+8
+2
+8
+8
+1
+8
+3
+8
+9
+8
+8
+0
+3
+0
+8
+8
+8
+8
+8
+8
+8
+8
+8
+6
+6
+8
+8
+9
+5
+7
+7
+3
+1
+8
+8
+5
+2
+2
+8
+3
+0
+2
+4
+0
+3
+4
+8
+8
+5
+8
+2
+7
+4
+6
+6
+8
+8
+5
+1
+2
+9
+8
+4
+7
+0
+1
+0
+1
+2
+5
+3
+6
+4
+2
+0
+9
+8
+7
+2
+6
+6
+1
+5
+9
+9
+4
+3
+1
+8
+9
+6
+2
+6
+1
+3
+6
+2
+9
+1
+5
+2
+0
+7
+4
+1
+7
+7
+4
+1
+0
+2
+3
+5
+3
+0
+1
+9
+7
+1
+0
+1
+1
+5
+2
+4
+2
+5
+4
+2
+9
+0
+4
+1
+7
+6
+7
+6
+9
+2
+7
+9
+4
+6
+0
+3
+0
+5
+6
+6
+4
+7
+2
+3
+7
+7
+7
+7
+5
+3
+2
+3
+3
+4
+4
+2
+9
+6
+1
+2
+3
+7
+1
+7
+2
+1
+7
+9
+0
+6
+0
+6
+1
+2
+5
+9
+5
+1
+7
+1
+6
+6
+2
+6
+1
+6
+3
+5
+7
+7
+7
+2
+2
+1
+6
+7
+9
+0
+5
+3
+1
+5
+3
+5
+9
+7
+0
+0
+4
+3
+0
+5
+1
+9
+2
+4
+7
+7
+5
+2
+3
+5
+7
+2
+2
+3
+3
+1
+4
+2
+0
+0
+0
+6
+1
+4
+6
+9
+5
+7
+8
+8
+2
+4
+8
+8
+2
+8
+7
+8
+9
+3
+8
+8
+8
+8
+6
+6
+3
+0
+3
+9
+1
+6
+7
+7
+0
+7
+0
+9
+2
+0
+7
+3
+0
+9
+0
+5
+5
+1
+6
+5
+6
+6
+4
+7
+0
+2
+6
+6
+3
+9
+2
+1
+7
+7
+2
+3
+3
+9
+1
+2
+4
+5
+9
+1
+6
+7
+3
+4
+2
+6
+1
+3
+2
+0
+7
+7
+7
+2
+9
+3
+5
+2
+3
+4
+4
+1
+4
+3
+0
+9
+5
+6
+1
+0
+4
+9
+0
+0
+1
+0
+3
+4
+9
+6
+4
+5
+4
+6
+3
+0
+9
+4
+7
+5
+2
+6
+0
+6
+9
+0
+1
+3
+7
+2
+4
+5
+6
+5
+2
+6
+6
+3
+2
+6
+5
+9
+7
+1
+1
+3
+9
+2
+2
+0
+5
+4
+2
+5
+1
+5
+7
+7
+0
+7
+0
+3
+7
+0
+5
+6
+5
+3
+9
+6
+6
+6
+0
+5
+2
+5
+7
+3
+2
+7
+4
+6
+7
+5
+9
+1
+3
+4
+2
+4
+4
+3
+2
+5
+3
+5
+0
+1
+4
+1
+4
+9
+3
+5
+3
+7
+0
+4
+9
+6
+2
+0
+5
+1
+0
+2
+0
+9
+3
+1
+6
+6
+1
+6
+5
+9
+1
+7
+8
+2
+9
+8
+6
+6
+8
+3
+8
+5
+9
+7
+8
+8
+8
+3
+8
+8
+6
+1
+8
+8
+8
+8
+7
+8
+9
+8
+8
+1
+8
+8
+1
+2
+3
+8
+4
+8
+7
+7
+5
+8
+3
+9
+0
+5
+8
+2
+8
+8
+9
+0
+7
+0
+1
+3
+2
+1
+9
+8
+5
+2
+6
+0
+2
+9
+6
+4
+5
+4
+9
+3
+7
+5
+0
+7
+0
+8
+9
+4
+3
+9
+2
+0
+0
+0
+8
+3
+7
+7
+5
+2
+6
+5
+0
+3
+9
+1
+0
+1
+0
+7
+9
+5
+6
+3
+3
+4
+6
+4
+5
+6
+5
+1
+4
+2
+6
+7
+6
+1
+0
+9
+7
+5
+2
+0
+1
+3
+6
+0
+6
+4
+3
+2
+4
+9
+9
+5
+2
+0
+3
+0
+2
+1
+0
+3
+2
+1
+7
+0
+9
+9
+2
+4
+1
+4
+4
+5
+9
+9
+7
+2
+7
+0
+9
+2
+9
+5
+5
+3
+2
+3
+9
+4
+2
+0
+5
+7
+5
+7
+6
+6
+1
+0
+2
+0
+6
+3
+9
+7
+5
+9
+2
+7
+9
+9
+2
+4
+7
+7
+4
+2
+9
+3
+6
+6
+1
+5
+4
+5
+9
+4
+3
+7
+2
+0
+6
+0
+6
+6
+3
+5
+6
+2
+4
+7
+5
+9
+6
+6
+3
+4
+9
+2
+1
+9
+7
+1
+3
+1
+5
+7
+6
+3
+4
+5
+7
+2
+1
+3
+0
+5
+0
+4
+1
+2
+8
+8
+7
+0
+8
+8
+8
+8
+8
+2
+8
+8
+8
+7
+8
+8
+9
+5
+0
+1
+0
+9
+2
+0
+9
+6
+1
+2
+6
+3
+0
+6
+2
+9
+8
+8
+8
+6
+8
+0
+3
+2
+6
+1
+8
+8
+5
+8
+6
+4
+8
+6
+4
+8
+2
+8
+3
+9
+8
+4
+8
+0
+8
+7
+5
+7
+5
+2
+7
+3
+9
+9
+6
+6
+6
+6
+1
+2
+1
+9
+6
+6
+1
+6
+7
+4
+4
+0
+4
+5
+2
+3
+1
+0
+3
+4
+3
+1
+6
+5
+2
+3
+7
+0
+1
+4
+5
+0
+9
+2
+9
+9
+0
+0
+4
+7
+4
+3
+7
+1
+3
+9
+2
+0
+6
+0
+1
+9
+0
+2
+7
+7
+2
+5
+1
+3
+6
+6
+0
+1
+5
+7
+6
+1
+7
+9
+0
+4
+9
+6
+6
+3
+3
+5
+1
+5
+9
+1
+0
+3
+4
+6
+3
+6
+9
+9
+6
+4
+7
+3
+5
+1
+9
+9
+7
+7
+1
+4
+7
+5
+9
+1
+0
+3
+0
+1
+3
+4
+7
+9
+4
+2
+6
+6
+3
+7
+4
+5
+6
+2
+9
+0
+3
+5
+1
+4
+4
+3
+7
+7
+1
+9
+5
+1
+0
+3
+9
+5
+2
+9
+1
+0
+2
+3
+8
+1
+8
+8
+8
+8
+8
+8
+1
+9
+5
+0
+7
+0
+8
+7
+8
+8
+7
+0
+8
+8
+8
+1
+8
+3
+8
+8
+8
+7
+2
+8
+5
+4
+4
+2
+4
+6
+1
+6
+2
+7
+6
+7
+5
+2
+0
+1
+8
+2
+6
+1
+3
+4
+4
+8
+4
+9
+1
+8
+3
+1
+7
+7
+1
+9
+6
+2
+2
+7
+0
+4
+0
+4
+5
+7
+4
+5
+3
+5
+0
+9
+8
+3
+3
+0
+9
+5
+7
+6
+0
+3
+0
+6
+9
+6
+5
+0
+2
+3
+3
+9
+6
+1
+7
+7
+7
+2
+1
+9
+7
+9
+2
+3
+4
+0
+5
+9
+5
+1
+7
+5
+0
+5
+0
+9
+7
+5
+4
+5
+9
+4
+0
+4
+4
+2
+7
+6
+9
+6
+2
+3
+3
+0
+4
+6
+5
+3
+6
+2
+6
+1
+7
+7
+4
+3
+4
+9
+1
+2
+5
+4
+6
+6
+1
+7
+0
+2
+3
+1
+9
+5
+2
+4
+4
+1
+0
+0
+9
+1
+5
+2
+3
+7
+4
+5
+1
+0
+0
+1
+2
+1
+0
+7
+9
+9
+2
+0
+7
+3
+2
+4
+0
+9
+2
+5
+6
+3
+3
+2
+0
+9
+7
+6
+1
+4
+3
+4
+4
+9
+1
+3
+5
+2
+4
+9
+2
+0
+7
+7
+5
+4
+3
+9
+7
+5
+0
+6
+9
+2
+2
+4
+0
+3
+2
+6
+9
+0
+3
+2
+6
+7
+1
+4
+9
+5
+8
+8
+2
+1
+8
+8
+8
+8
+5
+8
+8
+8
+8
+8
+8
+8
+2
+1
+5
+6
+7
+7
+9
+1
+1
+2
+4
+0
+4
+0
+1
+9
+7
+7
+3
+8
+9
+8
+8
+9
+8
+3
+3
+0
+9
+8
+8
+1
+8
+4
+3
+1
+4
+0
+7
+8
+6
+2
+1
+4
+8
+1
+4
+5
+1
+5
+7
+4
+3
+6
+4
+2
+4
+3
+6
+2
+3
+7
+0
+4
+2
+3
+6
+6
+9
+2
+1
+5
+0
+1
+4
+1
+9
+7
+5
+9
+7
+7
+7
+3
+5
+2
+9
+9
+0
+0
+2
+3
+6
+6
+6
+5
+4
+7
+1
+3
+6
+1
+7
+9
+5
+4
+4
+3
+4
+0
+9
+9
+6
+6
+7
+1
+9
+5
+6
+9
+5
+7
+1
+4
+9
+7
+4
+7
+5
+1
+7
+0
+0
+0
+5
+2
+1
+0
+1
+5
+9
+7
+3
+0
+3
+2
+0
+3
+1
+3
+1
+0
+3
+7
+2
+7
+9
+9
+2
+1
+4
+5
+4
+2
+9
+3
+0
+2
+5
+6
+5
+6
+9
+1
+7
+7
+1
+2
+5
+4
+4
+9
+2
+6
+3
+6
+2
+4
+1
+9
+5
+3
+0
+6
+6
+2
+9
+9
+1
+9
+2
+7
+0
+5
+9
+9
+0
+3
+8
+8
+9
+5
+8
+8
+8
+8
+8
+2
+8
+8
+8
+8
+8
+7
+9
+6
+6
+6
+6
+1
+2
+4
+9
+4
+4
+2
+7
+5
+7
+7
+2
+9
+3
+0
+8
+0
+8
+8
+7
+9
+3
+7
+5
+1
+0
+8
+8
+4
+4
+8
+8
+8
+5
+0
+8
+5
+8
+2
+6
+6
+7
+6
+9
+3
+3
+5
+1
+4
+9
+7
+6
+3
+7
+6
+6
+0
+9
+1
+4
+6
+2
+8
+1
+7
+6
+6
+5
+3
+7
+2
+4
+1
+8
+1
+0
+2
+6
+6
+3
+5
+9
+7
+5
+9
+2
+1
+3
+4
+9
+0
+1
+3
+2
+2
+3
+4
+5
+2
+2
+1
+3
+5
+3
+2
+0
+4
+6
+6
+3
+6
+3
+9
+6
+1
+4
+2
+5
+7
+3
+2
+1
+0
+6
+3
+0
+4
+0
+9
+2
+5
+7
+3
+2
+7
+1
+9
+0
+2
+5
+7
+9
+3
+2
+5
+7
+4
+0
+0
+4
+3
+6
+6
+5
+1
+5
+1
+9
+1
+3
+6
+2
+7
+1
+5
+9
+0
+3
+4
+4
+2
+2
+7
+9
+9
+1
+4
+6
+6
+4
+2
+5
+9
+0
+7
+3
+1
+7
+7
+9
+0
+1
+0
+2
+5
+5
+4
+9
+3
+4
+1
+3
+2
+1
+2
+0
+7
+0
+5
+3
+0
+9
+2
+9
+1
+5
+7
+0
+7
+7
+4
+4
+9
+4
+3
+1
+2
+6
+5
+9
+4
+6
+3
+4
+6
+7
+4
+0
+2
+0
+3
+7
+1
+2
+0
+5
+3
+7
+5
+1
+9
+7
+2
+1
+4
+7
+1
+0
+7
+0
+9
+2
+0
+1
+6
+2
+4
+7
+8
+8
+2
+8
+8
+8
+9
+2
+8
+6
+5
+4
+0
+8
+9
+8
+8
+7
+0
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+6
+8
+6
+0
+1
+8
+1
+3
+3
+1
+5
+8
+7
+5
+0
+1
+3
+8
+7
+4
+1
+4
+4
+3
+4
+0
+2
+8
+9
+1
+5
+4
+5
+0
+3
+8
+2
+9
+0
+4
+0
+3
+4
+1
+4
+9
+6
+6
+0
+4
+3
+8
+6
+6
+1
+6
+7
+1
+2
+4
+0
+4
+7
+2
+3
+4
+9
+2
+4
+9
+5
+2
+2
+6
+9
+4
+2
+4
+6
+6
+3
+2
+9
+5
+6
+1
+0
+6
+0
+5
+9
+6
+1
+9
+2
+3
+6
+7
+3
+9
+6
+6
+0
+2
+5
+4
+3
+9
+4
+1
+7
+3
+4
+2
+5
+9
+4
+5
+7
+4
+1
+0
+3
+9
+5
+1
+2
+3
+9
+4
+7
+0
+3
+0
+5
+3
+9
+3
+3
+4
+6
+7
+7
+1
+3
+3
+7
+5
+5
+4
+4
+0
+9
+3
+1
+6
+7
+1
+2
+5
+1
+8
+8
+3
+8
+8
+6
+6
+2
+9
+8
+3
+4
+2
+7
+8
+8
+8
+5
+6
+8
+8
+8
+8
+8
+8
+8
+0
+8
+0
+8
+8
+8
+8
+2
+7
+9
+6
+5
+1
+0
+5
+6
+2
+9
+7
+1
+9
+2
+4
+4
+8
+3
+1
+8
+9
+8
+8
+5
+0
+3
+5
+8
+9
+0
+5
+2
+4
+9
+4
+4
+5
+4
+7
+0
+2
+0
+1
+3
+7
+2
+1
+7
+3
+9
+2
+8
+4
+1
+4
+4
+3
+7
+6
+6
+6
+5
+4
+2
+2
+1
+3
+5
+2
+7
+5
+7
+6
+2
+3
+4
+1
+6
+6
+8
+5
+9
+9
+0
+6
+7
+7
+1
+0
+9
+1
+7
+5
+3
+0
+9
+6
+7
+7
+6
+2
+3
+4
+7
+0
+2
+9
+3
+0
+4
+2
+5
+0
+9
+2
+1
+4
+5
+4
+4
+7
+4
+6
+2
+0
+4
+0
+2
+6
+5
+3
+2
+4
+7
+9
+4
+2
+0
+3
+1
+2
+9
+4
+1
+0
+2
+3
+3
+1
+9
+2
+5
+4
+1
+5
+7
+0
+3
+9
+0
+1
+0
+7
+2
+5
+4
+9
+7
+7
+6
+6
+9
+2
+3
+9
+5
+1
+2
+6
+0
+4
+7
+9
+6
+5
+5
+3
+6
+6
+3
+6
+2
+2
+1
+6
+2
+6
+3
+5
+3
+2
+2
+0
+9
+1
+0
+4
+4
+5
+4
+7
+9
+3
+3
+2
+1
+4
+0
+4
+4
+3
+8
+8
+2
+0
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+0
+5
+7
+3
+7
+4
+5
+1
+7
+6
+3
+3
+1
+5
+6
+6
+9
+8
+2
+9
+0
+5
+7
+8
+8
+8
+3
+9
+8
+4
+8
+1
+5
+8
+8
+3
+2
+8
+8
+8
+8
+8
+6
+9
+8
+8
+8
+8
+8
+7
+7
+5
+1
+3
+8
+7
+5
+0
+3
+6
+9
+3
+1
+5
+2
+6
+3
+9
+6
+7
+4
+4
+7
+2
+3
+9
+5
+0
+2
+8
+4
+7
+6
+6
+3
+1
+0
+2
+4
+8
+4
+0
+3
+4
+7
+7
+1
+7
+5
+0
+2
+0
+8
+8
+0
+8
+2
+1
+9
+6
+1
+0
+1
+9
+5
+1
+3
+3
+1
+3
+5
+6
+6
+9
+1
+7
+6
+5
+2
+9
+0
+7
+4
+2
+6
+4
+6
+9
+1
+6
+5
+7
+2
+3
+7
+5
+2
+5
+0
+3
+7
+9
+1
+1
+6
+7
+3
+5
+6
+2
+0
+4
+9
+0
+2
+0
+1
+5
+4
+2
+5
+7
+7
+1
+2
+9
+6
+6
+2
+4
+6
+4
+6
+3
+0
+0
+0
+5
+4
+3
+1
+4
+9
+0
+0
+6
+3
+7
+4
+9
+5
+2
+9
+0
+0
+0
+0
+3
+4
+8
+7
+8
+8
+1
+3
+8
+9
+8
+8
+8
+8
+6
+6
+8
+1
+8
+8
+0
+0
+8
+3
+8
+8
+8
+5
+1
+8
+8
+1
+8
+8
+1
+8
+4
+5
+0
+6
+6
+6
+3
+0
+5
+1
+9
+7
+7
+3
+3
+8
+7
+7
+9
+4
+1
+9
+2
+1
+8
+8
+9
+7
+8
+4
+3
+7
+0
+9
+6
+4
+4
+6
+4
+0
+6
+5
+5
+3
+1
+8
+6
+7
+6
+6
+5
+1
+0
+7
+0
+4
+4
+9
+4
+3
+1
+8
+9
+0
+7
+7
+4
+2
+5
+3
+9
+7
+5
+0
+7
+5
+4
+3
+7
+1
+2
+9
+0
+0
+4
+5
+1
+8
+9
+2
+2
+7
+5
+3
+5
+2
+3
+4
+1
+2
+1
+3
+6
+6
+6
+6
+5
+6
+7
+7
+6
+6
+7
+1
+1
+6
+6
+0
+9
+0
+1
+9
+4
+1
+7
+7
+1
+9
+6
+5
+4
+1
+0
+6
+0
+9
+5
+1
+3
+5
+4
+5
+0
+9
+3
+2
+2
+4
+1
+5
+7
+9
+0
+1
+6
+6
+7
+4
+6
+3
+6
+6
+9
+4
+0
+1
+0
+3
+3
+5
+7
+0
+1
+7
+0
+1
+7
+0
+9
+1
+2
+9
+3
+5
+0
+2
+9
+7
+1
+5
+2
+5
+0
+0
+3
+9
+9
+9
+7
+7
+5
+7
+6
+9
+6
+6
+3
+4
+5
+1
+6
+6
+2
+5
+1
+0
+6
+4
+3
+4
+4
+2
+8
+8
+5
+3
+8
+8
+8
+0
+8
+2
+9
+7
+8
+8
+3
+1
+4
+0
+2
+3
+5
+9
+2
+4
+7
+5
+1
+3
+4
+1
+9
+1
+2
+8
+9
+8
+7
+3
+3
+7
+8
+8
+0
+1
+0
+6
+3
+8
+8
+4
+9
+8
+4
+7
+1
+8
+6
+1
+9
+6
+8
+8
+5
+8
+0
+9
+4
+2
+2
+7
+5
+1
+9
+9
+0
+7
+0
+2
+3
+0
+8
+9
+1
+3
+5
+4
+4
+8
+4
+7
+2
+3
+1
+8
+3
+4
+4
+5
+8
+2
+7
+6
+9
+4
+5
+4
+6
+6
+4
+2
+9
+1
+6
+1
+5
+6
+7
+3
+9
+5
+0
+9
+7
+0
+8
+3
+9
+2
+3
+0
+6
+6
+1
+4
+7
+9
+3
+2
+0
+0
+0
+0
+9
+3
+3
+7
+2
+1
+7
+0
+4
+7
+3
+5
+1
+2
+6
+1
+9
+6
+7
+5
+0
+7
+2
+1
+9
+4
+6
+4
+4
+1
+9
+5
+0
+9
+7
+7
+5
+7
+6
+6
+1
+0
+0
+1
+6
+4
+7
+4
+4
+2
+3
+4
+4
+2
+4
+9
+3
+5
+6
+6
+0
+4
+0
+9
+4
+3
+3
+2
+1
+0
+6
+0
+6
+6
+3
+7
+2
+5
+1
+9
+7
+0
+8
+8
+6
+6
+0
+7
+8
+8
+1
+5
+3
+8
+8
+8
+0
+8
+8
+8
+6
+5
+8
+8
+8
+8
+8
+8
+9
+8
+8
+5
+8
+8
+8
+4
+4
+2
+1
+8
+7
+7
+2
+3
+9
+9
+6
+2
+5
+6
+0
+2
+3
+1
+7
+6
+4
+7
+4
+8
+0
+6
+5
+1
+8
+4
+1
+7
+9
+2
+3
+0
+6
+6
+6
+5
+4
+1
+4
+2
+0
+0
+7
+3
+9
+9
+4
+8
+7
+0
+0
+1
+2
+9
+3
+5
+4
+2
+7
+3
+5
+0
+7
+0
+9
+6
+2
+3
+6
+4
+3
+4
+5
+6
+5
+3
+1
+6
+7
+7
+9
+0
+0
+0
+3
+5
+1
+0
+9
+4
+7
+7
+6
+4
+5
+5
+0
+9
+1
+5
+1
+3
+2
+1
+9
+9
+4
+5
+3
+5
+3
+2
+7
+9
+1
+6
+4
+4
+4
+5
+6
+9
+0
+4
+7
+7
+9
+6
+3
+2
+6
+6
+6
+6
+2
+4
+5
+1
+7
+6
+0
+6
+0
+2
+6
+9
+4
+0
+1
+5
+9
+1
+0
+9
+1
+6
+6
+2
+5
+3
+5
+2
+2
+0
+4
+1
+9
+9
+7
+7
+4
+5
+7
+5
+9
+1
+1
+4
+7
+1
+4
+0
+6
+3
+2
+7
+4
+6
+6
+7
+4
+3
+2
+0
+9
+0
+9
+2
+7
+3
+1
+7
+7
+7
+1
+9
+4
+1
+5
+1
+1
+2
+9
+4
+1
+6
+4
+7
+8
+8
+2
+1
+8
+8
+2
+8
+1
+8
+8
+8
+7
+8
+6
+5
+9
+5
+7
+0
+6
+0
+3
+4
+5
+2
+6
+9
+7
+7
+0
+7
+6
+9
+5
+8
+1
+8
+6
+3
+7
+7
+8
+2
+2
+4
+0
+1
+2
+4
+4
+1
+4
+8
+8
+8
+0
+2
+1
+5
+8
+1
+7
+7
+1
+0
+3
+4
+5
+4
+9
+2
+4
+9
+7
+7
+2
+6
+9
+4
+0
+5
+8
+0
+8
+2
+1
+3
+5
+1
+6
+6
+4
+5
+6
+0
+4
+0
+5
+8
+9
+9
+2
+1
+7
+4
+3
+0
+5
+9
+7
+2
+3
+4
+1
+2
+9
+1
+5
+3
+6
+5
+8
+5
+1
+2
+6
+7
+3
+3
+3
+0
+6
+6
+2
+3
+1
+3
+2
+7
+9
+9
+0
+5
+6
+1
+6
+4
+2
+4
+4
+0
+5
+7
+3
+7
+9
+2
+2
+3
+4
+3
+9
+6
+1
+7
+0
+4
+0
+4
+4
+2
+3
+0
+5
+1
+0
+3
+9
+1
+2
+7
+5
+7
+4
+3
+1
+4
+3
+2
+4
+6
+1
+7
+9
+5
+5
+0
+7
+2
+6
+6
+9
+6
+1
+6
+6
+2
+2
+6
+0
+5
+7
+6
+1
+7
+5
+1
+9
+3
+3
+5
+0
+5
+8
+8
+0
+4
+8
+7
+8
+8
+4
+5
+8
+8
+8
+6
+8
+4
+4
+1
+1
+5
+5
+1
+3
+0
+6
+4
+6
+6
+1
+3
+3
+5
+3
+7
+9
+1
+6
+2
+0
+6
+0
+8
+9
+8
+8
+1
+4
+8
+8
+1
+9
+8
+8
+5
+8
+7
+3
+8
+9
+2
+5
+8
+8
+8
+7
+2
+7
+4
+0
+2
+5
+3
+3
+1
+3
+9
+7
+7
+2
+0
+7
+7
+0
+5
+1
+8
+8
+3
+3
+6
+4
+2
+4
+6
+6
+3
+1
+3
+3
+9
+4
+6
+0
+0
+9
+0
+6
+1
+7
+4
+4
+7
+6
+0
+2
+6
+6
+5
+6
+2
+2
+1
+3
+0
+2
+7
+5
+7
+7
+1
+3
+7
+2
+4
+5
+0
+6
+5
+3
+6
+6
+7
+1
+9
+7
+6
+1
+5
+6
+1
+7
+3
+3
+9
+3
+0
+1
+5
+9
+2
+4
+3
+7
+1
+1
+2
+9
+5
+5
+2
+0
+4
+3
+7
+7
+9
+5
+3
+7
+7
+4
+5
+2
+9
+1
+3
+3
+4
+5
+6
+4
+2
+2
+3
+3
+4
+9
+4
+5
+0
+4
+5
+7
+3
+9
+6
+6
+4
+4
+3
+2
+5
+9
+6
+0
+9
+0
+4
+5
+2
+9
+0
+7
+2
+1
+0
+1
+3
+9
+9
+3
+6
+5
+2
+7
+1
+1
+0
+3
+9
+1
+4
+4
+3
+4
+5
+2
+2
+7
+1
+7
+3
+5
+9
+5
+0
+9
+0
+4
+3
+5
+6
+6
+1
+2
+5
+0
+0
+0
+0
+1
+7
+6
+2
+1
+0
+3
+1
+4
+1
+4
+7
+5
+3
+1
+5
+7
+4
+8
+8
+8
+2
+8
+8
+8
+5
+7
+9
+1
+8
+4
+3
+5
+8
+8
+8
+5
+3
+8
+8
+8
+8
+6
+8
+8
+5
+8
+8
+7
+8
+9
+9
+8
+2
+6
+6
+0
+7
+0
+5
+7
+6
+8
+2
+8
+4
+0
+9
+6
+4
+1
+4
+4
+8
+8
+9
+2
+7
+0
+5
+8
+1
+1
+9
+1
+0
+2
+0
+9
+7
+5
+4
+4
+1
+1
+2
+9
+0
+5
+9
+4
+8
+7
+5
+2
+7
+3
+1
+2
+4
+6
+4
+9
+6
+3
+4
+6
+0
+5
+9
+5
+1
+3
+5
+7
+4
+2
+4
+1
+5
+8
+5
+1
+5
+9
+9
+4
+0
+7
+0
+5
+7
+6
+9
+2
+4
+3
+7
+5
+1
+7
+9
+0
+2
+2
+6
+3
+0
+2
+1
+5
+6
+4
+0
+5
+1
+6
+7
+7
+4
+1
+6
+6
+0
+5
+9
+2
+3
+0
+3
+4
+6
+5
+0
+1
+2
+2
+3
+0
+4
+0
+2
+4
+0
+7
+5
+9
+5
+0
+4
+7
+7
+4
+0
+9
+1
+9
+5
+2
+4
+1
+3
+7
+7
+3
+1
+0
+5
+2
+0
+4
+1
+6
+7
+5
+6
+7
+2
+9
+9
+4
+6
+0
+5
+6
+1
+6
+9
+3
+0
+2
+2
+0
+9
+2
+8
+8
+5
+8
+1
+8
+3
+7
+2
+6
+6
+1
+0
+2
+8
+3
+8
+0
+1
+8
+8
+7
+9
+6
+6
+1
+8
+0
+8
+9
+9
+2
+4
+3
+7
+4
+6
+2
+0
+5
+6
+3
+1
+9
+5
+4
+3
+6
+6
+7
+2
+8
+5
+1
+4
+7
+0
+3
+0
+2
+8
+0
+7
+5
+3
+4
+5
+7
+2
+2
+1
+0
+3
+2
+4
+4
+0
+5
+9
+0
+0
+3
+0
+9
+7
+6
+5
+2
+3
+3
+6
+9
+1
+7
+9
+0
+5
+0
+6
+3
+2
+2
+0
+5
+1
+2
+3
+0
+9
+4
+7
+7
+6
+6
+2
+1
+9
+0
+1
+4
+1
+7
+7
+3
+9
+4
+7
+9
+3
+0
+5
+3
+7
+6
+6
+6
+5
+5
+9
+0
+2
+6
+6
+1
+3
+5
+1
+0
+7
+0
+2
+9
+4
+1
+4
+4
+4
+7
+0
+6
+9
+5
+3
+2
+2
+4
+5
+5
+9
+2
+5
+3
+4
+2
+1
+9
+0
+0
+0
+7
+5
+1
+2
+9
+3
+4
+3
+5
+0
+5
+4
+7
+0
+0
+0
+1
+2
+3
+6
+9
+2
+7
+7
+6
+6
+2
+4
+4
+7
+4
+6
+5
+6
+3
+2
+6
+4
+7
+7
+2
+1
+8
+8
+2
+6
+8
+8
+8
+8
+4
+8
+8
+1
+8
+5
+7
+4
+9
+5
+6
+9
+0
+2
+1
+3
+9
+2
+0
+1
+0
+5
+7
+7
+8
+6
+8
+7
+8
+8
+6
+3
+0
+4
+2
+5
+4
+7
+1
+3
+8
+8
+1
+2
+8
+8
+8
+8
+2
+8
+8
+8
+1
+8
+8
+5
+8
+5
+3
+1
+9
+0
+2
+9
+7
+7
+2
+8
+9
+5
+7
+7
+8
+1
+5
+2
+0
+4
+4
+3
+6
+6
+8
+6
+9
+2
+5
+7
+4
+3
+3
+8
+6
+9
+1
+0
+7
+4
+2
+5
+3
+9
+6
+2
+6
+3
+6
+6
+5
+8
+5
+9
+7
+3
+3
+0
+9
+2
+7
+1
+1
+3
+1
+5
+3
+7
+2
+7
+4
+3
+7
+3
+0
+5
+1
+2
+1
+3
+0
+0
+3
+9
+1
+5
+5
+1
+7
+7
+3
+2
+6
+6
+9
+2
+6
+6
+3
+0
+5
+1
+9
+7
+0
+5
+0
+1
+1
+0
+9
+3
+1
+9
+5
+1
+5
+4
+9
+3
+4
+9
+3
+6
+7
+5
+9
+9
+0
+3
+0
+7
+2
+0
+6
+6
+7
+7
+6
+1
+4
+6
+9
+9
+5
+2
+6
+5
+6
+2
+7
+9
+7
+3
+3
+0
+5
+4
+6
+2
+6
+6
+7
+5
+9
+7
+9
+1
+2
+0
+4
+3
+2
+2
+9
+9
+6
+2
+5
+7
+3
+7
+2
+9
+9
+3
+3
+2
+3
+5
+1
+4
+4
+0
+0
+3
+9
+1
+3
+9
+2
+1
+6
+5
+9
+9
+1
+7
+5
+2
+2
+6
+1
+7
+2
+1
+6
+6
+1
+3
+9
+4
+0
+0
+8
+4
+9
+2
+4
+1
+7
+7
+0
+0
+6
+3
+5
+6
+5
+8
+1
+0
+9
+6
+3
+4
+6
+4
+6
+2
+4
+8
+3
+0
+5
+4
+0
+1
+0
+2
+6
+6
+3
+5
+1
+7
+9
+9
+0
+1
+6
+1
+2
+5
+9
+9
+0
+2
+7
+7
+5
+7
+2
+9
+3
+4
+3
+2
+6
+6
+7
+7
+0
+3
+5
+1
+9
+0
+4
+0
+5
+1
+5
+7
+5
+2
+1
+9
+1
+4
+6
+4
+4
+4
+0
+9
+6
+1
+1
+2
+3
+0
+6
+6
+7
+3
+6
+5
+3
+1
+1
+4
+4
+0
+6
+6
+6
+6
+7
+4
+1
+2
+2
+1
+5
+1
+2
+5
+1
+4
+2
+9
+5
+0
+7
+0
+4
+1
+4
+2
+7
+6
+6
+6
+1
+0
+6
+9
+1
+9
+6
+1
+2
+3
+3
+9
+7
+7
+1
+3
+1
+2
+2
+7
+3
+1
+5
+2
+9
+7
+0
+3
+1
+4
+5
+1
+9
+1
+0
+0
+3
+5
+4
+0
+9
+7
+1
+9
+3
+4
+6
+6
+9
+3
+8
+8
+7
+4
+8
+8
+8
+8
+8
+8
+8
+8
+0
+8
+8
+1
+5
+3
+0
+7
+0
+6
+6
+6
+6
+3
+4
+5
+4
+7
+0
+9
+2
+6
+7
+6
+5
+2
+8
+0
+8
+0
+8
+1
+9
+7
+4
+7
+8
+5
+4
+7
+8
+8
+1
+9
+8
+1
+8
+2
+8
+5
+8
+9
+6
+6
+5
+2
+2
+5
+6
+1
+1
+0
+9
+3
+3
+2
+1
+4
+8
+8
+1
+4
+3
+4
+5
+7
+4
+8
+2
+5
+1
+0
+8
+2
+4
+0
+7
+7
+2
+2
+3
+4
+8
+4
+4
+9
+4
+6
+3
+5
+7
+5
+9
+9
+4
+0
+2
+8
+5
+6
+2
+6
+7
+4
+4
+0
+9
+5
+5
+9
+2
+3
+1
+6
+9
+2
+6
+9
+6
+3
+0
+1
+5
+6
+6
+6
+1
+5
+3
+6
+9
+7
+9
+5
+7
+3
+3
+2
+4
+9
+1
+9
+2
+1
+5
+4
+7
+9
+7
+1
+1
+0
+4
+5
+0
+5
+4
+0
+4
+3
+1
+2
+5
+6
+0
+4
+0
+4
+7
+2
+6
+4
+4
+2
+9
+5
+3
+2
+3
+7
+0
+4
+7
+4
+4
+7
+0
+2
+1
+0
+0
+1
+5
+9
+4
+5
+2
+5
+1
+7
+2
+6
+3
+9
+0
+5
+9
+0
+5
+3
+6
+7
+1
+7
+9
+9
+6
+0
+3
+6
+4
+1
+9
+6
+6
+0
+5
+0
+2
+7
+9
+5
+2
+9
+6
+4
+3
+6
+2
+5
+0
+3
+2
+1
+3
+7
+9
+9
+5
+1
+0
+2
+6
+4
+1
+9
+5
+3
+7
+1
+2
+7
+0
+9
+5
+4
+0
+3
+9
+5
+7
+8
+8
+8
+2
+4
+0
+1
+4
+2
+6
+6
+8
+2
+0
+5
+8
+8
+1
+8
+8
+1
+8
+8
+8
+8
+0
+8
+3
+5
+2
+9
+4
+9
+0
+1
+9
+7
+3
+4
+2
+7
+1
+6
+0
+2
+5
+7
+6
+6
+4
+3
+6
+6
+0
+9
+0
+7
+5
+3
+9
+6
+3
+1
+6
+0
+6
+2
+9
+3
+1
+5
+2
+1
+7
+0
+9
+1
+0
+9
+5
+2
+5
+4
+9
+4
+4
+9
+5
+1
+2
+7
+9
+5
+4
+2
+1
+7
+1
+0
+2
+0
+5
+4
+3
+6
+4
+1
+9
+9
+5
+4
+3
+4
+4
+5
+6
+7
+2
+6
+3
+0
+5
+4
+1
+9
+1
+3
+6
+7
+9
+7
+2
+9
+0
+5
+0
+2
+3
+0
+4
+2
+6
+3
+5
+7
+1
+7
+9
+1
+7
+3
+3
+4
+2
+2
+0
+5
+2
+3
+9
+6
+2
+1
+5
+6
+6
+3
+0
+9
+1
+0
+6
+4
+1
+6
+4
+5
+6
+5
+7
+2
+7
+4
+1
+9
+4
+9
+8
+8
+0
+1
+8
+8
+8
+8
+8
+8
+7
+8
+8
+8
+8
+4
+2
+1
+6
+3
+5
+9
+0
+4
+0
+2
+7
+7
+6
+6
+3
+6
+8
+5
+9
+8
+1
+3
+7
+7
+3
+6
+9
+2
+2
+0
+6
+1
+2
+8
+4
+8
+7
+5
+6
+6
+8
+8
+9
+8
+8
+3
+8
+0
+1
+7
+6
+9
+0
+4
+4
+3
+3
+0
+9
+2
+2
+7
+0
+3
+3
+7
+9
+8
+5
+2
+7
+0
+3
+0
+4
+9
+4
+3
+2
+5
+6
+6
+0
+5
+7
+3
+9
+1
+3
+4
+2
+2
+4
+5
+9
+2
+2
+9
+1
+2
+2
+7
+0
+7
+3
+9
+8
+4
+5
+2
+9
+8
+7
+7
+2
+1
+1
+4
+0
+9
+0
+9
+1
+5
+6
+6
+9
+9
+0
+1
+7
+4
+2
+0
+7
+7
+1
+2
+6
+6
+0
+2
+9
+3
+4
+5
+7
+7
+1
+0
+2
+4
+5
+3
+3
+2
+7
+7
+9
+1
+7
+4
+3
+7
+2
+5
+9
+9
+0
+2
+3
+4
+5
+4
+4
+9
+1
+3
+2
+4
+3
+4
+5
+0
+4
+7
+3
+1
+3
+0
+7
+2
+2
+3
+3
+5
+9
+2
+1
+9
+7
+1
+3
+0
+9
+0
+6
+5
+7
+2
+7
+9
+9
+9
+0
+5
+5
+3
+2
+9
+4
+7
+2
+2
+5
+7
+1
+9
+2
+1
+3
+2
+2
+3
+3
+0
+1
+0
+6
+6
+9
+2
+4
+1
+4
+0
+5
+2
+9
+5
+0
+6
+7
+1
+7
+7
+2
+6
+7
+5
+3
+4
+6
+6
+2
+3
+5
+9
+3
+7
+0
+4
+8
+8
+8
+8
+1
+8
+8
+5
+8
+9
+2
+8
+4
+8
+3
+1
+8
+8
+5
+3
+8
+8
+8
+8
+2
+8
+8
+8
+8
+6
+8
+8
+1
+0
+1
+8
+7
+3
+5
+8
+9
+5
+2
+7
+6
+0
+6
+6
+8
+9
+8
+2
+6
+4
+1
+6
+4
+1
+5
+7
+8
+3
+3
+0
+0
+5
+4
+2
+4
+1
+7
+7
+2
+2
+5
+4
+9
+0
+4
+9
+1
+3
+5
+0
+3
+7
+4
+5
+4
+3
+7
+1
+3
+6
+5
+6
+5
+7
+0
+2
+2
+9
+7
+1
+6
+6
+4
+5
+4
+2
+3
+6
+7
+6
+2
+3
+5
+1
+6
+7
+0
+5
+2
+3
+1
+9
+1
+2
+8
+5
+9
+8
+8
+8
+8
+8
+0
+8
+9
+8
+8
+2
+8
+8
+7
+7
+5
+4
+9
+4
+3
+5
+1
+4
+2
+3
+0
+9
+5
+4
+3
+8
+9
+0
+2
+0
+1
+4
+3
+4
+4
+5
+4
+6
+6
+6
+8
+8
+7
+8
+6
+6
+8
+8
+8
+8
+9
+8
+7
+7
+8
+2
+7
+5
+1
+0
+4
+0
+8
+2
+3
+9
+5
+4
+2
+6
+9
+0
+1
+9
+5
+8
+8
+5
+3
+0
+6
+9
+6
+6
+8
+3
+2
+8
+3
+1
+5
+4
+6
+6
+6
+3
+2
+9
+6
+5
+7
+2
+1
+3
+3
+0
+7
+7
+5
+1
+9
+4
+3
+4
+4
+0
+1
+0
+9
+5
+0
+5
+3
+1
+4
+0
+9
+9
+5
+7
+3
+4
+0
+4
+7
+9
+3
+1
+5
+1
+0
+5
+9
+3
+1
+6
+2
+7
+6
+1
+2
+9
+5
+3
+3
+2
+9
+6
+1
+9
+2
+3
+6
+7
+9
+2
+6
+9
+4
+2
+3
+6
+5
+7
+0
+4
+0
+3
+2
+7
+0
+0
+9
+5
+3
+5
+2
+5
+4
+1
+0
+0
+6
+3
+3
+9
+1
+5
+7
+6
+6
+6
+3
+4
+4
+5
+6
+6
+7
+7
+3
+4
+7
+4
+4
+7
+6
+0
+2
+9
+3
+4
+5
+1
+7
+3
+7
+0
+3
+1
+1
+4
+2
+3
+9
+9
+5
+1
+5
+1
+7
+7
+9
+9
+1
+6
+1
+0
+9
+5
+2
+3
+0
+7
+7
+2
+5
+6
+1
+3
+2
+1
+6
+6
+9
+4
+4
+9
+4
+5
+0
+6
+9
+3
+7
+7
+5
+1
+2
+4
+6
+9
+8
+4
+8
+4
+0
+7
+4
+9
+8
+8
+2
+8
+3
+8
+8
+8
+6
+8
+8
+8
+8
+8
+8
+8
+8
+8
+0
+8
+3
+8
+4
+6
+1
+3
+9
+7
+6
+5
+5
+4
+7
+0
+9
+0
+3
+2
+5
+8
+8
+3
+2
+8
+8
+8
+8
+8
+0
+7
+9
+2
+8
+8
+5
+1
+2
+0
+7
+3
+2
+1
+1
+5
+8
+2
+9
+9
+1
+2
+2
+8
+8
+4
+2
+7
+4
+0
+6
+0
+5
+6
+1
+3
+3
+5
+3
+7
+2
+1
+6
+6
+2
+5
+3
+4
+4
+2
+2
+1
+6
+1
+2
+0
+6
+6
+4
+9
+7
+5
+3
+2
+0
+0
+5
+9
+4
+9
+0
+6
+9
+4
+9
+4
+5
+3
+4
+5
+0
+2
+0
+7
+7
+3
+7
+2
+0
+5
+1
+9
+1
+3
+3
+2
+9
+1
+6
+7
+6
+3
+9
+0
+1
+9
+5
+1
+0
+4
+9
+4
+2
+7
+4
+0
+1
+5
+1
+5
+9
+2
+2
+3
+3
+7
+5
+2
+0
+9
+6
+2
+4
+6
+8
+4
+4
+8
+8
+5
+8
+8
+8
+8
+2
+6
+8
+8
+1
+8
+9
+6
+1
+4
+0
+1
+5
+6
+4
+2
+7
+5
+1
+2
+0
+3
+8
+9
+6
+1
+5
+8
+7
+0
+8
+3
+1
+8
+4
+1
+8
+5
+8
+9
+8
+8
+2
+8
+8
+7
+5
+9
+3
+0
+8
+6
+8
+8
+0
+3
+5
+7
+3
+4
+9
+5
+4
+1
+0
+2
+3
+7
+6
+2
+7
+7
+3
+0
+2
+0
+4
+8
+6
+3
+6
+5
+5
+7
+9
+1
+0
+3
+1
+4
+5
+9
+7
+7
+8
+3
+0
+8
+6
+9
+2
+6
+4
+5
+3
+2
+7
+6
+7
+2
+5
+3
+6
+6
+4
+9
+0
+9
+7
+2
+0
+7
+0
+5
+6
+1
+1
+0
+9
+4
+5
+4
+2
+2
+7
+7
+1
+2
+3
+1
+5
+2
+0
+5
+3
+5
+1
+9
+1
+4
+0
+2
+9
+5
+5
+9
+2
+4
+7
+4
+1
+0
+7
+0
+3
+5
+4
+1
+9
+3
+3
+0
+1
+4
+6
+6
+4
+3
+7
+7
+6
+0
+1
+4
+5
+0
+6
+3
+1
+5
+7
+7
+2
+4
+6
+3
+7
+2
+6
+6
+6
+6
+1
+4
+5
+0
+2
+0
+9
+9
+5
+2
+7
+7
+9
+9
+7
+5
+0
+2
+9
+1
+4
+6
+6
+6
+7
+7
+9
+4
+7
+6
+2
+7
+6
+6
+9
+0
+5
+0
+4
+2
+2
+7
+3
+7
+5
+1
+6
+6
+4
+2
+0
+9
+0
+7
+2
+0
+5
+3
+1
+9
+0
+4
+2
+3
+4
+1
+9
+2
+2
+5
+0
+2
+6
+6
+9
+7
+8
+8
+8
+1
+8
+2
+4
+8
+4
+6
+5
+7
+9
+1
+6
+4
+8
+8
+2
+8
+0
+8
+6
+5
+8
+8
+8
+8
+8
+8
+8
+8
+6
+2
+3
+6
+9
+7
+1
+0
+0
+0
+3
+4
+5
+4
+2
+3
+8
+0
+8
+8
+9
+7
+5
+2
+2
+5
+7
+7
+2
+0
+8
+1
+2
+6
+1
+9
+6
+1
+6
+0
+7
+7
+5
+9
+1
+5
+1
+3
+1
+0
+9
+9
+8
+4
+4
+3
+3
+7
+9
+9
+0
+0
+7
+2
+9
+1
+3
+9
+7
+7
+7
+1
+9
+3
+4
+5
+0
+6
+1
+0
+3
+4
+3
+9
+0
+1
+2
+1
+9
+5
+3
+6
+1
+4
+4
+2
+2
+3
+0
+1
+7
+6
+7
+6
+9
+9
+1
+6
+3
+5
+2
+4
+9
+1
+6
+6
+7
+7
+2
+5
+0
+3
+1
+2
+2
+0
+5
+1
+4
+7
+5
+3
+3
+2
+1
+5
+9
+1
+0
+0
+5
+0
+2
+7
+9
+9
+2
+0
+1
+0
+7
+2
+9
+9
+3
+4
+3
+4
+4
+1
+8
+4
+4
+8
+8
+8
+8
+8
+8
+5
+8
+1
+3
+2
+7
+8
+1
+3
+3
+5
+5
+4
+4
+9
+4
+3
+2
+1
+6
+0
+6
+7
+8
+0
+8
+3
+9
+8
+8
+1
+5
+4
+6
+7
+9
+2
+1
+9
+6
+6
+1
+0
+3
+1
+8
+8
+7
+8
+8
+8
+9
+8
+8
+0
+2
+6
+6
+1
+2
+2
+5
+7
+4
+2
+1
+5
+9
+9
+0
+4
+8
+1
+8
+5
+9
+4
+4
+9
+4
+5
+7
+3
+9
+6
+3
+2
+4
+7
+7
+7
+9
+9
+7
+4
+5
+6
+4
+0
+4
+9
+6
+6
+0
+4
+5
+0
+6
+3
+2
+6
+6
+1
+0
+4
+0
+3
+4
+2
+9
+0
+1
+2
+7
+3
+5
+7
+2
+5
+0
+1
+6
+3
+4
+6
+0
+2
+1
+5
+5
+6
+3
+7
+9
+6
+0
+7
+1
+5
+2
+0
+3
+6
+0
+0
+6
+0
+6
+7
+2
+9
+4
+6
+4
+2
+1
+0
+5
+2
+1
+6
+7
+1
+7
+4
+9
+9
+4
+9
+1
+3
+1
+2
+7
+4
+4
+2
+4
+3
+9
+3
+2
+5
+1
+4
+7
+4
+4
+3
+3
+0
+7
+5
+5
+4
+4
+2
+6
+6
+5
+6
+0
+1
+6
+3
+0
+5
+7
+2
+6
+6
+9
+4
+5
+1
+0
+6
+7
+2
+9
+7
+6
+9
+6
+7
+0
+5
+9
+3
+3
+9
+3
+4
+5
+7
+0
+1
+0
+7
+2
+7
+5
+6
+5
+2
+6
+5
+3
+6
+2
+9
+4
+0
+6
+4
+4
+6
+4
+9
+7
+3
+3
+0
+5
+4
+9
+5
+0
+3
+8
+3
+9
+8
+8
+4
+4
+1
+4
+0
+9
+8
+2
+7
+5
+4
+8
+8
+9
+8
+8
+1
+8
+8
+8
+8
+9
+5
+1
+8
+8
+8
+0
+3
+9
+9
+3
+8
+5
+2
+6
+6
+1
+9
+2
+1
+7
+6
+8
+1
+9
+0
+3
+2
+6
+6
+1
+3
+5
+8
+7
+5
+2
+0
+6
+6
+6
+4
+0
+7
+4
+2
+9
+1
+7
+7
+3
+2
+3
+8
+5
+2
+9
+3
+1
+5
+0
+4
+0
+7
+4
+3
+4
+0
+2
+1
+6
+6
+0
+3
+0
+1
+2
+4
+7
+4
+4
+3
+4
+4
+0
+5
+1
+5
+7
+5
+3
+2
+9
+8
+0
+2
+5
+1
+7
+7
+9
+7
+0
+0
+5
+3
+3
+4
+2
+1
+7
+7
+7
+2
+6
+6
+1
+9
+2
+9
+1
+3
+3
+1
+9
+9
+6
+2
+6
+6
+1
+6
+3
+9
+4
+4
+2
+0
+5
+0
+5
+6
+6
+5
+7
+2
+9
+1
+0
+9
+2
+5
+6
+6
+9
+3
+3
+0
+1
+2
+5
+7
+9
+4
+4
+9
+3
+7
+2
+4
+7
+9
+0
+7
+0
+1
+5
+2
+2
+9
+5
+3
+2
+2
+5
+0
+1
+7
+1
+7
+3
+6
+0
+5
+9
+6
+6
+1
+1
+8
+7
+8
+0
+3
+2
+4
+8
+4
+9
+1
+7
+3
+0
+2
+8
+8
+9
+7
+2
+3
+8
+0
+8
+6
+9
+8
+8
+2
+6
+6
+3
+1
+9
+9
+5
+3
+0
+1
+0
+7
+6
+6
+2
+0
+7
+3
+3
+6
+1
+9
+2
+1
+4
+5
+4
+2
+0
+9
+1
+3
+7
+7
+9
+6
+6
+1
+1
+5
+2
+4
+9
+4
+3
+7
+4
+1
+5
+2
+2
+1
+0
+9
+4
+2
+5
+3
+9
+5
+7
+7
+6
+6
+4
+3
+9
+3
+3
+5
+7
+4
+2
+0
+9
+9
+5
+2
+6
+6
+6
+5
+9
+0
+3
+4
+1
+7
+6
+6
+9
+2
+7
+0
+0
+0
+2
+1
+1
+2
+3
+6
+9
+1
+0
+9
+7
+4
+3
+1
+9
+6
+6
+6
+4
+0
+1
+2
+5
+6
+5
+4
+2
+4
+4
+0
+0
+0
+9
+9
+6
+6
+4
+5
+4
+7
+6
+1
+1
+3
+0
+4
+3
+4
+4
+2
+6
+3
+1
+2
+9
+1
+4
+5
+2
+3
+7
+7
+1
+2
+5
+4
+5
+7
+5
+1
+3
+9
+7
+7
+0
+0
+2
+3
+5
+6
+5
+2
+2
+1
+3
+2
+7
+9
+0
+7
+2
+5
+1
+6
+3
+9
+6
+6
+8
+8
+9
+8
+4
+8
+8
+6
+8
+8
+2
+8
+8
+5
+8
+8
+7
+7
+6
+2
+1
+0
+4
+5
+4
+2
+5
+3
+9
+2
+0
+4
+8
+9
+8
+8
+7
+2
+4
+7
+4
+9
+6
+1
+8
+0
+3
+4
+8
+8
+2
+8
+8
+7
+8
+8
+8
+8
+8
+8
+8
+8
+8
+5
+7
+5
+0
+7
+0
+3
+3
+1
+1
+9
+5
+4
+8
+3
+9
+5
+8
+9
+4
+8
+8
+1
+3
+2
+0
+9
+8
+8
+1
+6
+5
+6
+3
+2
+7
+4
+1
+3
+4
+4
+6
+6
+1
+6
+7
+7
+2
+7
+7
+6
+7
+7
+5
+3
+9
+2
+1
+4
+0
+6
+2
+3
+9
+0
+6
+2
+6
+6
+4
+0
+1
+9
+3
+1
+5
+4
+1
+5
+2
+9
+3
+9
+6
+2
+1
+4
+9
+2
+2
+0
+5
+7
+7
+2
+5
+9
+6
+6
+9
+6
+0
+0
+5
+6
+3
+2
+9
+1
+1
+7
+0
+3
+3
+7
+2
+7
+5
+9
+2
+0
+3
+0
+9
+2
+2
+9
+3
+5
+4
+5
+9
+5
+4
+2
+0
+4
+5
+7
+3
+9
+6
+6
+1
+7
+3
+0
+1
+2
+4
+5
+3
+3
+6
+6
+6
+0
+1
+7
+4
+3
+2
+3
+3
+1
+6
+2
+6
+6
+7
+7
+0
+5
+0
+1
+2
+4
+6
+1
+3
+9
+5
+9
+5
+2
+1
+7
+3
+2
+2
+1
+7
+5
+9
+5
+6
+9
+3
+2
+1
+0
+9
+0
+7
+9
+3
+5
+2
+5
+9
+4
+5
+9
+4
+7
+0
+2
+6
+6
+7
+4
+3
+0
+6
+1
+6
+4
+6
+9
+5
+1
+3
+2
+7
+7
+9
+9
+1
+4
+3
+5
+1
+5
+9
+3
+8
+8
+8
+8
+5
+7
+9
+1
+0
+5
+7
+8
+0
+1
+5
+9
+7
+5
+3
+5
+2
+4
+0
+9
+6
+3
+6
+6
+4
+2
+0
+9
+6
+6
+5
+4
+6
+4
+4
+7
+5
+3
+2
+2
+6
+6
+4
+1
+4
+3
+6
+7
+2
+0
+1
+4
+5
+4
+4
+3
+9
+1
+6
+9
+7
+7
+4
+7
+1
+5
+2
+0
+0
+0
+3
+4
+7
+0
+5
+2
+2
+0
+1
+3
+2
+9
+3
+1
+0
+6
+5
+3
+9
+2
+0
+0
+1
+0
+7
+3
+6
+9
+2
+6
+5
+4
+6
+0
+0
+7
+2
+5
+9
+1
+7
+3
+3
+5
+0
+2
+9
+4
+4
+3
+2
+4
+4
+0
+4
+0
+9
+9
+6
+6
+7
+4
+9
+5
+6
+3
+7
+7
+2
+4
+0
+9
+7
+2
+4
+0
+6
+6
+5
+9
+0
+4
+6
+6
+5
+6
+9
+2
+5
+7
+0
+5
+3
+5
+9
+0
+1
+3
+6
+3
+7
+5
+5
+9
+5
+2
+2
+3
+1
+0
+3
+1
+4
+5
+0
+1
+4
+7
+9
+2
+4
+3
+1
+3
+1
+2
+6
+9
+2
+6
+8
+8
+9
+4
+8
+0
+4
+2
+6
+1
+9
+6
+2
+8
+8
+0
+8
+8
+7
+8
+8
+2
+8
+8
+8
+8
+9
+8
+4
+7
+8
+1
+7
+9
+1
+0
+3
+0
+2
+4
+8
+6
+5
+2
+4
+7
+6
+2
+1
+9
+8
+8
+2
+8
+8
+6
+8
+9
+8
+1
+3
+4
+8
+8
+5
+6
+5
+6
+3
+5
+9
+6
+0
+9
+1
+3
+7
+0
+9
+7
+2
+9
+7
+7
+3
+2
+5
+1
+8
+5
+0
+3
+0
+7
+1
+7
+0
+9
+2
+1
+1
+0
+2
+4
+7
+7
+5
+2
+6
+1
+7
+9
+2
+1
+0
+3
+0
+2
+3
+5
+1
+2
+6
+4
+6
+4
+0
+7
+3
+9
+2
+4
+6
+5
+6
+6
+3
+0
+7
+7
+5
+3
+5
+4
+2
+0
+6
+6
+1
+3
+5
+9
+7
+2
+7
+0
+4
+0
+9
+1
+4
+1
+9
+5
+6
+3
+3
+0
+7
+0
+2
+6
+1
+5
+7
+2
+1
+0
+9
+2
+2
+9
+3
+5
+2
+7
+9
+1
+7
+3
+5
+7
+5
+4
+4
+9
+7
+5
+2
+5
+7
+1
+2
+5
+0
+3
+5
+3
+3
+1
+9
+0
+2
+4
+4
+1
+3
+7
+9
+9
+6
+2
+6
+4
+4
+7
+0
+1
+0
+7
+2
+3
+9
+4
+6
+6
+4
+5
+0
+2
+6
+6
+9
+9
+2
+7
+0
+3
+1
+2
+7
+9
+0
+2
+5
+3
+8
+8
+6
+8
+8
+8
+8
+7
+8
+8
+8
+8
+8
+8
+8
+8
+9
+7
+3
+4
+7
+4
+4
+7
+4
+5
+3
+9
+4
+2
+0
+1
+6
+2
+6
+6
+6
+1
+5
+3
+7
+5
+2
+5
+1
+8
+2
+7
+4
+9
+7
+5
+5
+1
+0
+2
+2
+4
+4
+1
+7
+7
+9
+3
+0
+3
+3
+1
+4
+7
+9
+9
+5
+7
+2
+0
+6
+0
+1
+9
+3
+9
+3
+0
+6
+5
+9
+6
+2
+7
+3
+6
+5
+2
+7
+9
+6
+6
+0
+1
+3
+7
+5
+9
+6
+4
+1
+5
+9
+1
+0
+9
+4
+1
+3
+5
+5
+7
+0
+9
+1
+3
+7
+7
+3
+2
+9
+5
+1
+4
+4
+3
+4
+4
+0
+7
+0
+1
+2
+3
+6
+6
+9
+2
+0
+3
+5
+2
+9
+7
+4
+7
+2
+6
+6
+3
+0
+2
+5
+1
+5
+0
+1
+9
+3
+2
+0
+1
+4
+5
+7
+3
+1
+0
+2
+4
+0
+3
+2
+9
+3
+0
+5
+2
+6
+6
+0
+2
+0
+5
+6
+5
+9
+1
+4
+0
+6
+2
+3
+5
+9
+6
+6
+6
+3
+4
+1
+0
+5
+6
+4
+3
+7
+7
+6
+2
+9
+0
+7
+3
+5
+2
+1
+4
+8
+9
+8
+1
+8
+4
+7
+8
+8
+9
+1
+8
+8
+1
+2
+8
+8
+1
+9
+8
+8
+8
+8
+8
+1
+8
+5
+0
+2
+0
+6
+6
+3
+2
+7
+7
+4
+3
+1
+8
+6
+1
+0
+6
+0
+4
+2
+0
+7
+6
+0
+7
+1
+5
+6
+2
+3
+9
+8
+8
+2
+3
+0
+1
+0
+7
+1
+0
+5
+1
+7
+7
+6
+6
+0
+5
+0
+9
+6
+6
+1
+8
+0
+4
+7
+3
+6
+6
+8
+0
+5
+1
+9
+5
+0
+2
+4
+6
+7
+6
+9
+9
+6
+4
+1
+2
+1
+4
+7
+9
+1
+3
+5
+7
+4
+7
+4
+9
+2
+1
+3
+8
+0
+5
+5
+4
+4
+9
+2
+0
+9
+1
+1
+2
+5
+3
+4
+5
+1
+0
+7
+1
+7
+6
+3
+1
+7
+7
+0
+6
+5
+3
+1
+6
+3
+2
+7
+5
+0
+0
+2
+6
+0
+5
+0
+2
+6
+5
+7
+7
+9
+9
+3
+4
+7
+3
+5
+3
+9
+6
+4
+5
+0
+2
+0
+3
+9
+4
+5
+9
+4
+7
+2
+3
+4
+2
+4
+1
+5
+6
+6
+3
+6
+6
+7
+7
+9
+5
+7
+5
+3
+7
+5
+4
+4
+3
+4
+9
+2
+1
+7
+5
+7
+4
+4
+1
+5
+1
+3
+2
+9
+5
+1
+4
+4
+0
+3
+2
+7
+1
+0
+3
+3
+0
+4
+0
+9
+1
+1
+6
+0
+5
+7
+4
+6
+7
+8
+8
+0
+8
+8
+8
+8
+8
+7
+8
+1
+8
+8
+2
+8
+0
+6
+1
+2
+4
+3
+4
+4
+9
+1
+7
+5
+3
+3
+5
+9
+9
+4
+8
+6
+8
+2
+7
+1
+4
+0
+4
+4
+8
+4
+3
+5
+9
+8
+0
+8
+8
+1
+8
+3
+8
+8
+8
+7
+5
+6
+6
+3
+2
+5
+4
+6
+0
+4
+1
+6
+1
+2
+2
+3
+4
+5
+4
+4
+7
+7
+2
+7
+7
+3
+9
+5
+0
+4
+0
+2
+3
+6
+6
+2
+4
+4
+1
+9
+2
+2
+9
+0
+1
+2
+6
+5
+0
+6
+3
+1
+7
+4
+2
+9
+3
+6
+6
+3
+5
+5
+7
+9
+3
+7
+7
+3
+7
+6
+4
+4
+6
+4
+5
+6
+6
+3
+7
+1
+4
+5
+1
+5
+0
+5
+1
+0
+4
+0
+3
+5
+0
+1
+5
+2
+9
+5
+3
+0
+4
+3
+7
+9
+5
+2
+7
+1
+3
+9
+0
+5
+9
+6
+2
+2
+3
+3
+0
+9
+9
+1
+6
+2
+7
+3
+6
+2
+7
+0
+0
+4
+1
+3
+4
+2
+2
+4
+1
+9
+9
+3
+0
+7
+5
+2
+6
+7
+9
+1
+4
+4
+4
+5
+2
+9
+1
+3
+6
+0
+6
+0
+0
+7
+7
+8
+8
+8
+4
+6
+4
+4
+1
+8
+8
+5
+7
+2
+5
+1
+8
+8
+8
+6
+8
+8
+2
+8
+8
+8
+8
+8
+8
+8
+8
+5
+8
+5
+4
+0
+1
+0
+5
+7
+2
+2
+3
+1
+4
+9
+1
+4
+1
+8
+1
+3
+8
+9
+7
+0
+9
+1
+5
+7
+8
+9
+6
+6
+6
+7
+7
+3
+5
+3
+9
+7
+2
+2
+1
+6
+6
+3
+5
+6
+5
+6
+6
+3
+0
+1
+0
+7
+7
+5
+4
+4
+8
+4
+9
+2
+1
+9
+0
+1
+9
+7
+7
+2
+4
+6
+6
+4
+0
+3
+0
+6
+6
+1
+4
+3
+9
+5
+0
+6
+6
+6
+3
+7
+7
+1
+4
+4
+5
+6
+5
+6
+6
+3
+4
+7
+1
+4
+9
+5
+3
+3
+5
+1
+4
+2
+3
+5
+9
+7
+2
+7
+0
+9
+2
+4
+9
+3
+0
+5
+3
+7
+9
+2
+1
+1
+5
+3
+2
+0
+9
+1
+2
+6
+1
+3
+6
+2
+1
+4
+3
+6
+6
+5
+3
+1
+9
+0
+4
+0
+1
+4
+0
+1
+6
+2
+4
+6
+3
+9
+6
+4
+1
+5
+2
+7
+5
+9
+4
+4
+9
+0
+7
+1
+2
+3
+5
+5
+9
+4
+3
+7
+3
+9
+1
+7
+7
+1
+0
+6
+9
+6
+6
+6
+4
+2
+5
+4
+3
+3
+0
+1
+7
+6
+2
+2
+9
+3
+0
+0
+0
+6
+1
+9
+9
+3
+5
+8
+8
+7
+8
+8
+8
+8
+0
+3
+8
+9
+8
+8
+7
+1
+8
+7
+0
+5
+7
+2
+5
+4
+1
+4
+6
+0
+0
+6
+0
+6
+4
+0
+8
+9
+1
+8
+6
+2
+3
+6
+4
+1
+5
+4
+1
+7
+2
+3
+1
+9
+6
+2
+8
+8
+8
+1
+8
+9
+8
+7
+4
+0
+5
+1
+5
+0
+9
+8
+4
+2
+0
+7
+1
+3
+9
+2
+5
+8
+2
+2
+0
+5
+9
+1
+2
+0
+3
+0
+7
+9
+9
+6
+6
+5
+6
+0
+2
+1
+6
+0
+1
+7
+3
+3
+9
+0
+9
+1
+7
+5
+3
+4
+7
+0
+2
+0
+5
+7
+4
+2
+9
+9
+5
+6
+6
+0
+7
+9
+4
+3
+7
+4
+4
+9
+1
+6
+6
+3
+4
+7
+7
+1
+6
+7
+9
+7
+2
+6
+4
+6
+6
+2
+9
+5
+0
+1
+5
+1
+4
+6
+0
+3
+6
+1
+6
+9
+5
+5
+3
+2
+2
+4
+1
+5
+7
+5
+1
+7
+2
+2
+0
+9
+3
+1
+3
+3
+4
+7
+7
+9
+0
+8
+8
+4
+8
+8
+8
+8
+8
+8
+7
+8
+8
+8
+8
+8
+6
+2
+3
+3
+4
+3
+6
+4
+9
+4
+7
+5
+6
+3
+5
+7
+4
+8
+8
+5
+4
+3
+2
+4
+8
+4
+8
+9
+8
+7
+6
+0
+7
+8
+8
+7
+8
+8
+8
+8
+8
+8
+8
+6
+8
+2
+8
+8
+8
+8
+2
+9
+9
+5
+6
+5
+1
+7
+7
+9
+9
+3
+0
+7
+8
+0
+5
+6
+6
+3
+8
+8
+2
+2
+7
+9
+8
+1
+5
+7
+7
+4
+2
+0
+1
+1
+0
+3
+5
+9
+4
+1
+7
+4
+3
+2
+0
+4
+1
+9
+9
+2
+5
+0
+2
+1
+6
+4
+5
+4
+1
+3
+6
+9
+2
+4
+9
+5
+3
+1
+7
+3
+1
+6
+4
+6
+4
+4
+2
+9
+5
+9
+6
+1
+3
+6
+6
+9
+1
+7
+9
+0
+5
+3
+1
+2
+0
+5
+4
+7
+5
+0
+9
+7
+2
+7
+6
+1
+3
+5
+9
+1
+6
+2
+3
+6
+6
+2
+9
+7
+7
+0
+2
+0
+3
+3
+9
+0
+1
+6
+6
+9
+7
+6
+1
+3
+5
+1
+4
+9
+3
+1
+5
+6
+4
+0
+5
+0
+3
+3
+9
+3
+0
+7
+7
+1
+6
+0
+9
+3
+7
+5
+1
+9
+9
+7
+7
+4
+0
+1
+0
+6
+9
+6
+4
+3
+1
+2
+1
+7
+6
+7
+3
+1
+4
+6
+2
+9
+0
+6
+3
+6
+6
+3
+7
+5
+2
+1
+6
+6
+3
+3
+4
+0
+9
+2
+5
+7
+4
+3
+0
+1
+0
+1
+2
+5
+1
+3
+1
+2
+9
+0
+0
+8
+8
+3
+8
+7
+8
+8
+8
+8
+8
+8
+8
+5
+2
+8
+8
+9
+6
+6
+0
+7
+7
+5
+3
+4
+5
+2
+1
+1
+3
+0
+4
+7
+7
+0
+5
+2
+8
+8
+1
+1
+4
+4
+8
+4
+8
+0
+5
+8
+9
+8
+8
+8
+8
+7
+8
+6
+3
+8
+8
+8
+8
+6
+2
+2
+0
+7
+1
+3
+6
+9
+5
+6
+2
+1
+0
+7
+7
+9
+7
+7
+1
+6
+4
+3
+0
+4
+8
+1
+9
+1
+5
+3
+7
+8
+2
+4
+9
+6
+5
+5
+0
+3
+4
+7
+2
+4
+3
+3
+4
+3
+9
+9
+5
+4
+3
+1
+8
+2
+0
+5
+0
+5
+3
+7
+4
+9
+6
+6
+6
+0
+2
+6
+1
+5
+2
+9
+5
+6
+2
+1
+7
+4
+7
+7
+4
+4
+5
+4
+3
+0
+1
+0
+9
+2
+1
+7
+3
+2
+5
+3
+0
+2
+4
+2
+4
+9
+3
+4
+7
+5
+0
+2
+6
+7
+3
+3
+9
+5
+0
+0
+2
+3
+1
+3
+4
+6
+6
+7
+3
+9
+7
+5
+4
+3
+2
+6
+6
+5
+9
+7
+9
+3
+7
+2
+1
+0
+9
+6
+2
+6
+5
+5
+2
+9
+0
+7
+0
+1
+7
+0
+1
+9
+5
+8
+3
+8
+4
+8
+7
+1
+2
+0
+1
+8
+8
+8
+8
+8
+9
+8
+8
+3
+8
+1
+8
+8
+8
+8
+3
+8
+8
+4
+8
+8
+1
+4
+8
+1
+8
+8
+1
+0
+4
+0
+4
+4
+2
+1
+0
+8
+2
+1
+8
+3
+8
+8
+8
+8
+8
+8
+2
+3
+1
+0
+5
+7
+6
+8
+1
+2
+9
+3
+7
+2
+5
+6
+6
+7
+6
+3
+5
+6
+0
+5
+6
+0
+9
+6
+5
+6
+1
+1
+2
+7
+9
+5
+8
+1
+8
+9
+6
+6
+3
+1
+5
+5
+0
+9
+5
+9
+3
+2
+1
+4
+1
+2
+0
+4
+5
+4
+7
+7
+7
+8
+2
+5
+4
+3
+6
+4
+5
+7
+7
+2
+4
+3
+4
+1
+2
+4
+9
+0
+2
+0
+6
+6
+4
+2
+7
+5
+3
+1
+6
+7
+4
+9
+1
+6
+3
+5
+7
+3
+1
+0
+7
+1
+3
+5
+1
+5
+9
+1
+5
+2
+3
+9
+6
+3
+2
+1
+4
+0
+3
+0
+6
+9
+9
+2
+6
+7
+1
+1
+5
+0
+9
+7
+7
+4
+7
+9
+3
+7
+5
+1
+0
+2
+2
+9
+3
+5
+2
+5
+7
+6
+2
+9
+4
+0
+7
+0
+2
+0
+5
+9
+2
+1
+4
+3
+0
+7
+7
+1
+9
+2
+4
+3
+4
+4
+0
+4
+1
+7
+2
+7
+4
+7
+0
+2
+9
+3
+9
+3
+6
+5
+4
+9
+2
+6
+0
+8
+8
+0
+8
+8
+8
+8
+8
+8
+1
+9
+8
+8
+8
+8
+2
+5
+6
+6
+4
+1
+9
+4
+3
+3
+2
+4
+1
+7
+9
+7
+1
+7
+9
+1
+8
+5
+1
+8
+3
+6
+9
+6
+6
+1
+8
+2
+5
+8
+8
+1
+8
+8
+8
+8
+8
+8
+4
+8
+8
+2
+8
+8
+8
+6
+2
+5
+6
+4
+8
+0
+5
+1
+9
+3
+4
+7
+4
+2
+7
+0
+9
+7
+7
+8
+8
+8
+2
+2
+9
+0
+5
+6
+6
+1
+3
+4
+2
+3
+0
+5
+0
+9
+4
+7
+6
+2
+7
+6
+6
+6
+0
+4
+5
+3
+2
+6
+6
+9
+4
+2
+3
+1
+6
+8
+5
+9
+7
+6
+4
+4
+6
+4
+7
+1
+9
+0
+1
+2
+4
+3
+0
+5
+9
+5
+0
+5
+2
+1
+4
+9
+5
+2
+1
+7
+0
+3
+0
+9
+9
+5
+7
+1
+0
+9
+9
+4
+6
+4
+3
+3
+6
+5
+9
+2
+0
+1
+7
+2
+7
+9
+1
+7
+0
+2
+3
+3
+1
+2
+7
+1
+9
+0
+1
+7
+5
+3
+2
+0
+9
+0
+3
+5
+4
+6
+7
+2
+5
+7
+3
+7
+7
+3
+9
+4
+5
+6
+3
+6
+6
+3
+9
+1
+4
+0
+8
+9
+4
+8
+8
+6
+6
+8
+8
+0
+8
+5
+1
+3
+8
+8
+8
+0
+8
+8
+8
+8
+8
+8
+5
+9
+8
+7
+8
+0
+8
+1
+2
+9
+9
+4
+3
+1
+0
+7
+1
+5
+9
+8
+4
+2
+5
+8
+0
+9
+8
+1
+8
+3
+2
+6
+7
+9
+0
+6
+0
+3
+1
+5
+9
+1
+3
+8
+1
+9
+0
+4
+2
+8
+5
+1
+8
+9
+7
+1
+9
+7
+3
+5
+1
+2
+8
+9
+5
+8
+1
+7
+0
+6
+6
+4
+1
+4
+5
+5
+3
+9
+7
+7
+7
+5
+6
+0
+5
+9
+9
+6
+6
+4
+0
+4
+0
+2
+5
+7
+7
+6
+4
+2
+4
+5
+4
+2
+6
+0
+6
+0
+7
+4
+9
+4
+0
+1
+1
+5
+1
+0
+3
+3
+0
+2
+1
+7
+3
+0
+9
+3
+5
+7
+7
+2
+6
+9
+9
+1
+0
+4
+5
+9
+2
+1
+7
+3
+6
+3
+0
+9
+5
+6
+6
+0
+4
+4
+0
+4
+7
+1
+6
+5
+1
+6
+2
+9
+5
+9
+1
+5
+0
+4
+9
+2
+1
+4
+3
+3
+2
+7
+7
+6
+2
+1
+6
+1
+1
+9
+4
+5
+6
+4
+1
+7
+5
+2
+9
+1
+9
+6
+5
+4
+6
+3
+0
+7
+6
+6
+6
+9
+3
+4
+9
+4
+2
+0
+5
+6
+4
+3
+9
+7
+7
+2
+0
+0
+0
+2
+9
+2
+4
+5
+2
+8
+8
+3
+8
+3
+8
+7
+8
+8
+8
+1
+8
+3
+1
+8
+8
+9
+3
+3
+4
+5
+4
+4
+7
+6
+3
+0
+6
+0
+1
+6
+2
+4
+9
+7
+3
+6
+6
+1
+4
+8
+4
+4
+3
+7
+5
+8
+0
+7
+9
+6
+8
+1
+8
+2
+8
+8
+9
+8
+8
+8
+4
+0
+1
+5
+4
+1
+2
+9
+1
+5
+7
+2
+6
+6
+4
+1
+4
+4
+0
+1
+2
+0
+6
+0
+8
+6
+7
+8
+0
+8
+1
+9
+8
+2
+5
+7
+5
+6
+3
+9
+9
+0
+0
+5
+0
+5
+3
+9
+9
+3
+7
+4
+2
+5
+3
+9
+5
+2
+4
+1
+8
+2
+3
+6
+9
+2
+2
+0
+4
+4
+2
+4
+3
+3
+9
+6
+6
+0
+4
+7
+1
+4
+7
+5
+2
+7
+0
+5
+9
+6
+6
+4
+5
+2
+3
+7
+7
+3
+5
+3
+5
+6
+2
+0
+3
+1
+4
+3
+1
+9
+1
+4
+2
+0
+5
+1
+0
+9
+3
+1
+3
+0
+5
+0
+7
+9
+0
+9
+3
+7
+7
+9
+6
+1
+6
+4
+3
+3
+7
+9
+2
+0
+4
+0
+3
+5
+0
+1
+2
+0
+9
+7
+7
+3
+7
+9
+0
+2
+5
+5
+9
+0
+4
+3
+9
+8
+4
+8
+8
+8
+2
+3
+9
+8
+8
+2
+6
+8
+6
+8
+8
+7
+8
+8
+6
+0
+8
+8
+8
+8
+8
+4
+5
+8
+8
+3
+0
+7
+1
+4
+6
+6
+2
+2
+9
+1
+0
+7
+0
+5
+3
+7
+9
+8
+7
+8
+0
+8
+8
+3
+9
+1
+8
+5
+7
+2
+3
+1
+9
+3
+2
+0
+1
+1
+3
+2
+1
+3
+1
+4
+2
+7
+3
+4
+2
+8
+5
+1
+8
+9
+4
+6
+6
+4
+8
+7
+5
+2
+1
+4
+5
+5
+7
+0
+9
+6
+5
+5
+0
+3
+2
+1
+7
+0
+3
+1
+4
+4
+7
+4
+9
+0
+3
+0
+2
+8
+1
+6
+4
+6
+6
+0
+3
+9
+4
+5
+4
+4
+2
+4
+3
+6
+2
+2
+0
+7
+7
+6
+5
+7
+5
+6
+9
+6
+1
+1
+4
+0
+6
+0
+7
+1
+7
+6
+3
+2
+1
+3
+0
+6
+5
+7
+7
+1
+9
+2
+1
+5
+0
+2
+4
+4
+1
+4
+2
+0
+0
+7
+7
+9
+5
+6
+6
+7
+1
+1
+0
+2
+9
+5
+4
+1
+2
+4
+6
+7
+9
+2
+6
+3
+4
+4
+5
+9
+3
+1
+2
+6
+6
+6
+4
+5
+0
+4
+5
+2
+1
+4
+9
+1
+3
+3
+5
+9
+4
+0
+7
+4
+3
+4
+6
+6
+6
+1
+0
+1
+0
+6
+6
+5
+1
+6
+7
+6
+1
+3
+2
+9
+7
+8
+8
+2
+8
+8
+8
+8
+8
+8
+8
+0
+7
+0
+8
+8
+5
+2
+5
+0
+4
+2
+4
+4
+9
+5
+2
+7
+7
+3
+2
+3
+9
+4
+8
+5
+1
+9
+3
+2
+4
+8
+4
+1
+2
+9
+1
+5
+2
+8
+8
+8
+8
+2
+3
+8
+8
+6
+2
+7
+6
+8
+3
+4
+9
+3
+0
+2
+4
+6
+6
+7
+6
+3
+1
+6
+0
+9
+9
+8
+5
+3
+5
+6
+0
+1
+0
+7
+7
+5
+2
+5
+8
+9
+5
+0
+1
+3
+2
+1
+9
+7
+6
+7
+7
+3
+6
+6
+6
+5
+3
+5
+2
+4
+6
+9
+6
+7
+0
+5
+4
+2
+5
+7
+1
+1
+3
+0
+0
+9
+2
+0
+5
+4
+3
+7
+7
+9
+0
+2
+4
+7
+1
+4
+5
+9
+5
+9
+2
+7
+4
+0
+7
+9
+2
+5
+9
+6
+6
+1
+6
+7
+9
+3
+7
+1
+5
+2
+4
+6
+9
+1
+0
+4
+1
+6
+2
+0
+6
+7
+2
+6
+0
+5
+6
+2
+9
+0
+5
+5
+2
+4
+0
+6
+3
+4
+5
+3
+0
+1
+6
+9
+1
+2
+1
+7
+2
+9
+0
+9
+3
+7
+7
+1
+4
+4
+0
+5
+3
+3
+1
+7
+7
+7
+1
+8
+5
+6
+4
+8
+1
+4
+8
+8
+8
+7
+0
+1
+0
+2
+9
+8
+8
+5
+8
+8
+8
+8
+8
+8
+8
+3
+8
+2
+8
+8
+8
+5
+2
+4
+8
+9
+5
+7
+7
+1
+3
+2
+5
+3
+4
+2
+6
+8
+3
+8
+8
+9
+7
+8
+2
+2
+0
+6
+6
+9
+8
+1
+9
+7
+5
+7
+1
+3
+9
+0
+6
+0
+4
+1
+3
+9
+1
+2
+1
+4
+7
+5
+2
+3
+0
+7
+4
+1
+3
+4
+8
+0
+9
+5
+0
+5
+2
+7
+3
+4
+9
+3
+5
+7
+1
+2
+5
+7
+6
+4
+0
+7
+3
+0
+3
+0
+9
+4
+0
+2
+6
+8
+6
+7
+9
+6
+1
+2
+7
+1
+3
+3
+1
+7
+1
+5
+9
+5
+3
+1
+5
+2
+4
+9
+7
+0
+9
+3
+5
+7
+7
+9
+6
+4
+3
+2
+6
+6
+6
+5
+9
+7
+7
+4
+3
+3
+0
+1
+0
+6
+6
+7
+3
+3
+7
+6
+9
+4
+6
+4
+6
+3
+1
+9
+9
+0
+4
+2
+0
+3
+5
+3
+5
+6
+1
+1
+2
+9
+6
+5
+9
+1
+7
+0
+1
+9
+4
+4
+9
+7
+1
+0
+5
+3
+2
+1
+4
+1
+2
+6
+7
+9
+7
+5
+2
+0
+9
+0
+2
+1
+9
+6
+7
+7
+5
+5
+4
+2
+9
+3
+9
+2
+2
+1
+6
+6
+6
+0
+7
+6
+0
+2
+0
+7
+3
+8
+8
+1
+8
+8
+8
+8
+8
+8
+8
+9
+8
+7
+8
+6
+3
+3
+0
+7
+7
+6
+4
+0
+6
+0
+6
+6
+1
+5
+7
+5
+2
+6
+0
+9
+8
+8
+8
+5
+4
+1
+4
+3
+0
+4
+0
+8
+3
+8
+8
+9
+5
+8
+8
+2
+3
+8
+8
+9
+8
+8
+4
+7
+7
+2
+3
+3
+1
+0
+7
+4
+3
+5
+2
+1
+7
+6
+1
+0
+4
+8
+8
+3
+9
+8
+5
+2
+0
+1
+6
+6
+9
+5
+1
+5
+2
+4
+3
+9
+9
+7
+6
+5
+6
+0
+2
+6
+5
+3
+0
+2
+6
+0
+3
+6
+5
+1
+7
+2
+7
+2
+3
+7
+4
+3
+4
+4
+1
+2
+4
+1
+2
+6
+6
+0
+9
+0
+3
+6
+4
+3
+2
+4
+9
+5
+2
+6
+6
+6
+5
+9
+6
+7
+7
+0
+1
+0
+8
+9
+9
+4
+1
+6
+2
+7
+7
+5
+9
+2
+5
+4
+3
+9
+2
+0
+0
+9
+3
+3
+5
+3
+7
+9
+9
+1
+0
+5
+4
+6
+6
+1
+6
+7
+4
+4
+1
+9
+2
+3
+0
+6
+6
+1
+6
+9
+1
+3
+1
+0
+6
+5
+3
+7
+4
+6
+7
+4
+3
+2
+0
+5
+0
+3
+4
+7
+6
+6
+7
+2
+9
+1
+4
+7
+5
+0
+5
+0
+2
+3
+0
+7
+7
+0
+5
+1
+9
+3
+9
+0
+1
+5
+4
+9
+6
+0
+1
+5
+7
+1
+0
+9
+1
+2
+4
+8
+8
+8
+2
+9
+8
+8
+0
+1
+8
+8
+8
+7
+8
+8
+8
+8
+2
+8
+1
+8
+4
+4
+3
+7
+1
+3
+5
+9
+4
+0
+3
+1
+5
+5
+2
+9
+9
+8
+4
+2
+0
+8
+7
+9
+2
+8
+5
+5
+6
+3
+0
+9
+6
+1
+6
+0
+3
+2
+0
+1
+6
+1
+2
+6
+3
+0
+2
+3
+9
+7
+7
+2
+3
+4
+7
+4
+9
+5
+6
+4
+5
+1
+4
+7
+9
+0
+7
+1
+3
+9
+5
+3
+4
+4
+0
+4
+1
+5
+2
+2
+9
+1
+4
+2
+5
+3
+5
+3
+2
+1
+4
+5
+1
+4
+0
+6
+6
+7
+7
+5
+9
+1
+6
+3
+1
+2
+0
+9
+9
+2
+5
+1
+7
+1
+2
+1
+3
+7
+2
+5
+1
+5
+1
+9
+9
+3
+1
+3
+6
+4
+7
+0
+0
+2
+3
+3
+4
+2
+2
+1
+7
+5
+3
+6
+5
+9
+2
+9
+9
+0
+4
+6
+4
+4
+6
+4
+9
+6
+3
+7
+2
+5
+0
+6
+6
+0
+3
+0
+5
+9
+4
+7
+4
+4
+7
+4
+3
+0
+2
+2
+9
+4
+1
+2
+2
+3
+7
+7
+7
+1
+4
+3
+2
+9
+1
+8
+8
+2
+8
+8
+8
+8
+8
+3
+1
+8
+8
+6
+5
+8
+2
+0
+5
+0
+0
+2
+3
+1
+9
+6
+2
+6
+6
+0
+3
+9
+9
+8
+2
+1
+8
+8
+1
+8
+8
+7
+7
+9
+5
+1
+0
+2
+8
+8
+8
+1
+8
+8
+8
+8
+8
+6
+8
+0
+1
+8
+3
+7
+5
+3
+5
+4
+9
+6
+0
+8
+8
+1
+6
+7
+9
+8
+4
+4
+3
+6
+8
+5
+6
+8
+3
+8
+1
+3
+0
+9
+7
+8
+2
+1
+4
+5
+2
+6
+9
+1
+5
+0
+7
+0
+4
+3
+5
+4
+0
+5
+1
+3
+8
+9
+9
+5
+7
+5
+3
+2
+5
+1
+9
+6
+1
+4
+6
+0
+3
+4
+7
+5
+0
+2
+3
+6
+1
+0
+6
+6
+5
+6
+2
+9
+6
+3
+2
+0
+4
+7
+5
+2
+1
+3
+9
+7
+2
+0
+4
+0
+2
+1
+4
+7
+1
+5
+9
+4
+6
+3
+5
+1
+6
+6
+4
+1
+9
+0
+2
+0
+7
+6
+9
+2
+4
+3
+1
+4
+2
+0
+9
+6
+1
+3
+6
+9
+2
+7
+0
+5
+0
+5
+4
+3
+5
+2
+9
+7
+3
+2
+2
+2
+5
+7
+7
+1
+3
+3
+0
+9
+0
+1
+9
+5
+2
+7
+4
+1
+9
+4
+9
+7
+1
+0
+3
+6
+9
+2
+6
+7
+3
+7
+0
+3
+6
+5
+2
+6
+4
+6
+6
+4
+1
+0
+0
+1
+5
+0
+3
+0
+9
+3
+6
+7
+1
+5
+4
+9
+4
+0
+7
+6
+0
+7
+3
+9
+9
+0
+2
+0
+1
+5
+3
+2
+9
+5
+7
+2
+3
+1
+9
+7
+7
+6
+6
+4
+2
+0
+3
+1
+5
+5
+4
+1
+3
+6
+9
+3
+7
+2
+8
+8
+3
+7
+5
+3
+8
+0
+8
+9
+1
+0
+3
+3
+2
+3
+0
+9
+5
+1
+9
+3
+4
+3
+1
+7
+4
+4
+3
+7
+9
+0
+1
+6
+6
+5
+4
+2
+5
+4
+6
+7
+0
+7
+7
+1
+6
+4
+5
+4
+9
+6
+0
+0
+0
+5
+4
+5
+7
+6
+6
+1
+0
+3
+2
+9
+4
+1
+2
+5
+3
+3
+0
+3
+9
+0
+6
+0
+2
+1
+0
+3
+1
+2
+1
+7
+4
+0
+7
+9
+9
+4
+7
+5
+3
+1
+0
+3
+0
+5
+2
+6
+5
+7
+6
+7
+7
+5
+6
+2
+1
+3
+5
+3
+2
+5
+3
+1
+2
+5
+9
+1
+7
+1
+4
+9
+4
+7
+0
+4
+4
+2
+1
+9
+6
+3
+2
+4
+1
+7
+1
+2
+9
+0
+3
+0
+6
+4
+0
+4
+7
+6
+3
+3
+5
+7
+7
+6
+9
+2
+6
+3
+6
+0
+4
+0
+9
+1
+2
+8
+8
+3
+8
+8
+8
+8
+8
+8
+8
+9
+8
+8
+8
+8
+8
+5
+6
+2
+4
+9
+9
+2
+3
+3
+0
+1
+5
+7
+1
+7
+2
+4
+3
+9
+8
+5
+8
+1
+0
+7
+1
+9
+7
+3
+6
+8
+8
+8
+3
+9
+8
+8
+8
+2
+8
+7
+7
+6
+0
+8
+0
+4
+2
+8
+3
+1
+2
+4
+5
+0
+5
+2
+3
+3
+4
+1
+6
+4
+7
+1
+0
+7
+8
+8
+8
+5
+8
+6
+9
+3
+6
+7
+0
+2
+4
+0
+1
+3
+2
+6
+6
+9
+4
+2
+7
+0
+7
+0
+2
+9
+5
+6
+2
+6
+6
+0
+8
+9
+1
+5
+7
+2
+7
+3
+5
+7
+2
+2
+4
+4
+2
+4
+7
+9
+9
+5
+0
+7
+3
+3
+2
+5
+9
+5
+0
+5
+1
+3
+4
+0
+7
+0
+9
+2
+3
+6
+1
+6
+9
+1
+0
+1
+2
+5
+1
+1
+7
+6
+1
+6
+0
+9
+0
+3
+5
+6
+5
+0
+0
+7
+7
+3
+9
+5
+1
+2
+3
+3
+5
+3
+0
+0
+0
+2
+3
+4
+1
+3
+2
+6
+6
+7
+9
+5
+4
+3
+6
+1
+2
+4
+3
+6
+2
+6
+6
+7
+5
+9
+1
+1
+9
+2
+0
+6
+1
+6
+5
+7
+3
+4
+2
+1
+5
+9
+9
+2
+3
+0
+5
+4
+5
+9
+9
+7
+2
+3
+1
+5
+4
+4
+9
+4
+3
+1
+2
+9
+7
+5
+9
+1
+5
+7
+2
+9
+1
+9
+4
+2
+4
+4
+6
+0
+2
+9
+1
+6
+6
+5
+7
+9
+6
+0
+9
+0
+1
+2
+4
+8
+9
+8
+5
+8
+0
+1
+2
+2
+1
+3
+8
+8
+7
+8
+0
+8
+8
+6
+8
+8
+8
+8
+8
+8
+4
+4
+8
+8
+8
+8
+8
+3
+6
+1
+5
+6
+1
+6
+6
+7
+9
+5
+2
+1
+0
+9
+9
+0
+4
+5
+0
+4
+3
+9
+5
+3
+2
+7
+4
+1
+3
+4
+0
+5
+1
+2
+0
+7
+0
+4
+9
+4
+9
+1
+2
+2
+1
+0
+4
+2
+1
+8
+1
+5
+2
+9
+3
+6
+0
+7
+5
+4
+6
+1
+9
+7
+5
+2
+5
+6
+6
+7
+2
+0
+3
+6
+6
+9
+5
+4
+1
+6
+4
+5
+6
+7
+2
+7
+7
+5
+9
+3
+6
+9
+1
+5
+9
+0
+3
+7
+4
+3
+9
+1
+2
+2
+1
+3
+5
+2
+9
+5
+0
+7
+7
+0
+7
+5
+2
+1
+4
+0
+4
+4
+5
+4
+6
+6
+1
+4
+3
+1
+9
+0
+1
+2
+7
+9
+4
+4
+9
+4
+5
+1
+2
+1
+4
+0
+9
+0
+7
+7
+7
+5
+3
+3
+1
+6
+2
+0
+3
+8
+8
+2
+8
+8
+8
+8
+8
+6
+0
+8
+3
+8
+8
+8
+2
+9
+7
+3
+4
+2
+6
+6
+6
+9
+2
+6
+0
+3
+0
+1
+5
+4
+9
+7
+6
+1
+8
+3
+4
+5
+9
+4
+2
+7
+7
+3
+1
+8
+9
+5
+0
+8
+5
+8
+8
+8
+9
+8
+3
+8
+4
+4
+8
+5
+9
+0
+4
+0
+3
+2
+0
+4
+1
+8
+5
+6
+3
+0
+6
+2
+9
+8
+3
+5
+6
+3
+8
+0
+2
+6
+6
+7
+3
+3
+1
+4
+2
+0
+7
+0
+9
+3
+0
+5
+0
+2
+3
+1
+3
+3
+2
+4
+0
+5
+2
+9
+5
+3
+9
+0
+6
+8
+1
+5
+9
+3
+6
+5
+4
+4
+1
+4
+6
+5
+6
+3
+7
+2
+0
+0
+0
+7
+7
+6
+1
+7
+5
+5
+3
+4
+1
+2
+2
+1
+3
+7
+9
+1
+4
+3
+5
+9
+0
+1
+9
+2
+3
+5
+7
+2
+7
+4
+5
+0
+3
+3
+4
+9
+2
+2
+5
+0
+0
+3
+6
+9
+4
+5
+2
+7
+6
+1
+0
+3
+9
+7
+7
+1
+3
+0
+1
+2
+9
+5
+0
+6
+2
+6
+6
+9
+5
+2
+4
+4
+3
+4
+1
+0
+9
+0
+2
+2
+1
+3
+2
+1
+4
+7
+4
+4
+5
+0
+7
+2
+6
+1
+0
+9
+3
+5
+6
+2
+2
+6
+5
+6
+3
+3
+4
+0
+1
+2
+2
+9
+7
+6
+1
+6
+6
+4
+0
+5
+9
+1
+3
+7
+7
+5
+4
+2
+9
+3
+9
+0
+5
+0
+4
+9
+1
+7
+0
+5
+7
+2
+2
+1
+5
+8
+8
+8
+8
+3
+8
+8
+5
+8
+0
+8
+8
+3
+8
+6
+6
+8
+8
+5
+8
+8
+8
+8
+8
+8
+4
+7
+8
+3
+0
+8
+8
+6
+2
+4
+3
+9
+8
+1
+6
+8
+1
+0
+4
+9
+4
+2
+9
+8
+8
+8
+5
+9
+8
+7
+7
+2
+1
+5
+3
+9
+2
+0
+1
+2
+6
+9
+4
+3
+1
+6
+6
+4
+7
+9
+7
+3
+9
+7
+4
+1
+0
+2
+6
+9
+9
+6
+2
+5
+3
+0
+0
+7
+9
+7
+7
+0
+1
+5
+3
+3
+5
+2
+5
+7
+3
+0
+9
+0
+6
+5
+0
+5
+4
+4
+2
+0
+9
+5
+1
+6
+7
+9
+2
+2
+9
+0
+6
+7
+2
+9
+4
+6
+4
+4
+6
+4
+0
+6
+9
+4
+9
+3
+5
+6
+5
+2
+9
+7
+7
+0
+2
+5
+4
+7
+9
+2
+1
+3
+1
+9
+0
+5
+9
+4
+3
+1
+7
+3
+1
+0
+0
+0
+0
+2
+2
+5
+7
+9
+0
+1
+3
+1
+2
+9
+1
+9
+5
+2
+3
+6
+1
+8
+8
+1
+8
+2
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+1
+5
+1
+4
+0
+0
+4
+9
+5
+9
+7
+1
+6
+3
+3
+6
+3
+1
+0
+8
+9
+5
+7
+4
+6
+2
+4
+8
+5
+8
+0
+9
+8
+8
+8
+8
+7
+7
+6
+1
+3
+5
+8
+8
+8
+4
+1
+2
+2
+7
+6
+5
+9
+4
+4
+3
+4
+2
+8
+0
+9
+9
+2
+5
+0
+7
+2
+1
+9
+0
+2
+3
+5
+4
+0
+2
+0
+1
+8
+3
+2
+2
+7
+0
+9
+5
+1
+5
+5
+3
+3
+1
+6
+7
+5
+0
+5
+4
+3
+7
+1
+9
+5
+0
+6
+0
+3
+4
+2
+4
+4
+1
+9
+4
+3
+2
+4
+0
+7
+3
+2
+2
+5
+4
+6
+6
+0
+0
+9
+2
+1
+9
+8
+4
+7
+7
+9
+0
+6
+1
+1
+5
+6
+4
+5
+9
+7
+2
+6
+5
+6
+6
+1
+9
+4
+6
+5
+2
+5
+7
+7
+0
+3
+7
+4
+0
+5
+1
+9
+9
+2
+5
+0
+7
+1
+2
+0
+9
+6
+5
+2
+0
+1
+3
+7
+9
+0
+7
+3
+2
+9
+7
+9
+9
+7
+4
+3
+4
+4
+5
+4
+6
+2
+2
+7
+1
+0
+4
+4
+9
+5
+3
+2
+6
+1
+4
+7
+7
+6
+6
+5
+2
+3
+6
+6
+6
+4
+6
+1
+6
+9
+6
+7
+5
+7
+3
+3
+0
+7
+1
+2
+4
+1
+3
+4
+1
+0
+2
+6
+0
+5
+6
+2
+5
+4
+7
+1
+6
+7
+7
+3
+2
+6
+5
+5
+3
+2
+1
+7
+7
+5
+7
+5
+8
+9
+8
+8
+8
+3
+2
+1
+7
+9
+5
+5
+3
+8
+8
+8
+8
+0
+8
+8
+0
+3
+8
+8
+4
+9
+8
+4
+6
+3
+0
+8
+4
+0
+9
+0
+3
+8
+8
+3
+6
+5
+7
+6
+5
+0
+6
+8
+2
+9
+1
+6
+3
+0
+6
+7
+8
+9
+7
+8
+3
+5
+4
+5
+6
+5
+2
+7
+5
+1
+3
+2
+1
+4
+9
+5
+0
+5
+3
+4
+2
+9
+9
+7
+7
+5
+7
+3
+5
+7
+9
+8
+3
+4
+1
+1
+2
+1
+4
+5
+1
+7
+4
+6
+6
+2
+1
+6
+0
+3
+9
+0
+6
+0
+3
+6
+0
+6
+7
+5
+4
+0
+3
+4
+5
+3
+0
+8
+2
+8
+8
+8
+1
+8
+8
+3
+8
+8
+8
+1
+8
+8
+0
+7
+7
+1
+2
+2
+3
+5
+9
+2
+0
+4
+5
+1
+3
+9
+9
+3
+1
+8
+8
+9
+8
+0
+3
+1
+8
+2
+8
+7
+6
+6
+5
+3
+0
+7
+2
+6
+6
+8
+1
+2
+8
+4
+8
+9
+7
+1
+8
+6
+6
+3
+0
+4
+9
+6
+6
+7
+7
+0
+4
+0
+9
+4
+1
+5
+8
+0
+2
+0
+4
+4
+3
+4
+7
+1
+5
+9
+1
+0
+4
+0
+2
+7
+5
+6
+2
+6
+6
+9
+5
+6
+1
+7
+3
+2
+4
+3
+5
+2
+7
+0
+3
+1
+3
+5
+1
+4
+9
+2
+7
+0
+3
+9
+2
+3
+9
+4
+1
+0
+0
+9
+3
+3
+9
+1
+4
+7
+3
+9
+4
+2
+9
+4
+1
+5
+2
+6
+5
+3
+4
+2
+0
+6
+7
+0
+1
+3
+5
+3
+6
+4
+7
+4
+9
+6
+7
+3
+1
+2
+4
+6
+9
+3
+6
+0
+0
+6
+1
+5
+7
+4
+7
+2
+5
+1
+0
+6
+2
+0
+3
+0
+7
+9
+7
+9
+9
+2
+3
+3
+4
+2
+1
+5
+9
+3
+1
+3
+7
+5
+2
+0
+9
+7
+5
+6
+1
+5
+6
+2
+3
+0
+5
+0
+9
+6
+0
+7
+2
+5
+1
+3
+9
+0
+5
+1
+3
+2
+4
+3
+4
+4
+5
+0
+7
+7
+2
+3
+9
+9
+9
+5
+0
+5
+3
+7
+7
+7
+4
+1
+2
+7
+0
+4
+0
+3
+6
+0
+4
+1
+3
+6
+9
+2
+6
+6
+5
+7
+7
+1
+4
+4
+0
+2
+1
+9
+6
+8
+0
+8
+7
+1
+8
+5
+8
+8
+3
+8
+0
+8
+8
+8
+8
+8
+8
+8
+5
+8
+8
+8
+8
+8
+3
+1
+8
+4
+2
+5
+9
+1
+2
+0
+8
+3
+1
+9
+9
+6
+6
+2
+1
+8
+7
+2
+1
+4
+3
+7
+2
+3
+5
+6
+9
+2
+4
+4
+8
+1
+4
+4
+5
+7
+3
+9
+7
+3
+2
+5
+4
+1
+5
+4
+5
+0
+9
+8
+4
+7
+7
+1
+5
+6
+1
+2
+6
+0
+3
+9
+4
+5
+7
+5
+0
+6
+6
+9
+9
+3
+2
+6
+5
+1
+2
+1
+9
+3
+7
+6
+6
+0
+1
+7
+7
+3
+5
+2
+2
+1
+4
+0
+2
+2
+4
+3
+7
+2
+2
+9
+0
+1
+0
+3
+0
+7
+5
+9
+9
+7
+0
+7
+7
+1
+4
+4
+1
+4
+9
+0
+0
+6
+0
+5
+4
+5
+3
+3
+0
+9
+5
+1
+4
+6
+2
+4
+6
+4
+6
+7
+7
+6
+6
+3
+0
+9
+0
+2
+9
+7
+3
+1
+2
+7
+1
+0
+2
+8
+8
+8
+8
+8
+7
+8
+8
+2
+5
+8
+6
+8
+8
+8
+8
+3
+2
+2
+5
+5
+7
+6
+3
+4
+1
+7
+0
+0
+0
+6
+5
+0
+3
+1
+2
+2
+1
+7
+1
+2
+3
+0
+9
+1
+2
+1
+8
+4
+8
+9
+8
+8
+5
+8
+4
+8
+3
+4
+8
+5
+6
+0
+8
+7
+1
+4
+2
+4
+5
+5
+0
+1
+0
+1
+4
+3
+4
+4
+6
+7
+7
+9
+5
+3
+6
+0
+6
+0
+3
+2
+9
+3
+0
+1
+5
+6
+0
+9
+3
+2
+6
+6
+6
+5
+2
+4
+0
+7
+2
+3
+7
+6
+3
+7
+3
+3
+5
+2
+5
+9
+7
+2
+3
+7
+7
+5
+0
+7
+0
+7
+3
+6
+6
+6
+9
+2
+5
+0
+0
+2
+0
+9
+9
+7
+4
+4
+0
+4
+2
+7
+9
+4
+1
+5
+4
+3
+5
+2
+9
+2
+5
+1
+4
+9
+1
+3
+5
+4
+0
+5
+3
+2
+2
+0
+4
+5
+2
+7
+7
+3
+5
+0
+9
+6
+6
+4
+3
+5
+7
+3
+9
+5
+1
+4
+2
+6
+6
+0
+2
+0
+5
+6
+6
+9
+9
+7
+9
+0
+2
+6
+6
+9
+3
+3
+1
+1
+7
+5
+3
+0
+3
+1
+7
+3
+5
+6
+4
+1
+9
+4
+9
+2
+1
+7
+7
+9
+9
+0
+3
+3
+2
+5
+1
+9
+9
+2
+4
+3
+7
+1
+7
+5
+9
+6
+6
+3
+6
+6
+0
+5
+0
+5
+4
+3
+4
+4
+2
+4
+3
+7
+7
+9
+4
+4
+9
+4
+3
+1
+0
+9
+2
+5
+4
+6
+5
+4
+7
+8
+9
+8
+8
+8
+1
+8
+5
+7
+6
+8
+2
+1
+8
+5
+3
+8
+8
+8
+8
+8
+8
+6
+3
+8
+2
+8
+5
+8
+8
+8
+3
+4
+1
+2
+6
+7
+7
+5
+2
+1
+3
+7
+2
+0
+1
+9
+0
+2
+9
+3
+5
+4
+2
+8
+1
+1
+9
+3
+7
+8
+5
+1
+5
+7
+3
+2
+4
+3
+4
+9
+7
+4
+0
+3
+1
+3
+6
+9
+6
+5
+3
+3
+1
+7
+6
+0
+7
+6
+3
+1
+6
+5
+1
+9
+1
+1
+3
+3
+6
+5
+9
+2
+0
+0
+0
+7
+1
+4
+6
+1
+5
+2
+5
+3
+5
+2
+9
+1
+3
+7
+3
+3
+6
+9
+2
+6
+6
+0
+4
+5
+4
+7
+1
+2
+6
+5
+3
+9
+2
+1
+9
+5
+2
+5
+3
+6
+0
+3
+7
+4
+7
+4
+2
+9
+5
+3
+2
+0
+0
+7
+1
+0
+9
+5
+9
+2
+4
+1
+4
+4
+9
+4
+1
+3
+2
+2
+5
+9
+3
+2
+9
+7
+7
+0
+6
+9
+3
+6
+5
+1
+6
+0
+0
+7
+7
+1
+3
+2
+5
+6
+6
+6
+6
+7
+7
+5
+1
+7
+6
+7
+9
+1
+4
+4
+6
+6
+2
+0
+5
+0
+1
+3
+0
+5
+9
+0
+3
+0
+5
+8
+8
+6
+9
+6
+6
+5
+8
+0
+2
+6
+9
+8
+3
+8
+8
+0
+4
+2
+7
+4
+3
+8
+2
+8
+8
+6
+4
+1
+5
+4
+7
+9
+7
+9
+9
+5
+4
+1
+4
+4
+2
+8
+9
+1
+2
+2
+7
+3
+5
+5
+9
+7
+1
+1
+6
+9
+0
+3
+1
+5
+0
+0
+0
+7
+9
+1
+6
+2
+2
+5
+6
+6
+9
+2
+1
+8
+3
+6
+3
+9
+6
+1
+0
+6
+5
+5
+2
+1
+8
+7
+4
+4
+6
+4
+6
+0
+3
+0
+1
+5
+2
+7
+7
+9
+2
+7
+7
+7
+1
+2
+4
+4
+9
+4
+2
+1
+1
+0
+2
+9
+3
+5
+6
+9
+4
+6
+4
+0
+7
+4
+4
+9
+5
+5
+0
+2
+4
+3
+7
+9
+2
+5
+3
+1
+2
+3
+1
+9
+1
+2
+9
+3
+0
+7
+2
+1
+9
+4
+1
+2
+3
+3
+5
+3
+9
+1
+6
+2
+0
+7
+7
+4
+9
+0
+1
+7
+2
+6
+6
+9
+1
+1
+2
+5
+3
+9
+3
+7
+4
+6
+6
+4
+0
+9
+0
+6
+9
+7
+1
+2
+7
+4
+0
+6
+7
+2
+9
+5
+2
+2
+4
+4
+0
+4
+0
+1
+7
+8
+8
+8
+8
+8
+8
+8
+8
+8
+9
+8
+8
+8
+5
+7
+8
+9
+3
+0
+0
+3
+4
+4
+5
+2
+3
+1
+9
+3
+1
+6
+7
+2
+8
+8
+7
+3
+8
+8
+8
+8
+8
+0
+5
+9
+7
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+6
+8
+8
+5
+4
+5
+1
+3
+9
+1
+8
+4
+6
+6
+5
+3
+1
+5
+7
+7
+8
+4
+5
+8
+9
+1
+6
+6
+0
+8
+8
+2
+7
+4
+4
+7
+5
+1
+6
+6
+9
+9
+3
+6
+7
+8
+7
+5
+5
+0
+3
+4
+4
+1
+2
+3
+5
+9
+5
+1
+7
+7
+4
+2
+2
+9
+3
+0
+1
+2
+0
+5
+1
+2
+3
+7
+0
+1
+7
+4
+6
+5
+2
+6
+8
+4
+2
+1
+6
+3
+3
+0
+6
+0
+1
+4
+2
+3
+5
+1
+1
+9
+4
+3
+2
+3
+5
+0
+7
+9
+7
+5
+6
+6
+0
+4
+9
+0
+2
+4
+5
+4
+3
+0
+4
+1
+6
+6
+6
+0
+7
+4
+3
+5
+1
+5
+6
+1
+0
+6
+0
+2
+7
+0
+1
+5
+1
+5
+0
+9
+5
+6
+4
+5
+2
+5
+7
+9
+0
+7
+0
+3
+5
+2
+2
+1
+6
+0
+7
+0
+9
+3
+1
+2
+1
+5
+5
+1
+9
+0
+3
+9
+0
+4
+5
+4
+9
+1
+4
+6
+1
+2
+6
+6
+1
+2
+2
+5
+3
+7
+1
+6
+9
+0
+6
+0
+4
+6
+4
+5
+9
+9
+6
+0
+5
+6
+4
+6
+2
+7
+5
+9
+3
+0
+2
+0
+5
+9
+1
+4
+4
+2
+4
+9
+8
+3
+6
+7
+6
+4
+9
+4
+7
+0
+6
+6
+8
+6
+9
+4
+1
+0
+3
+0
+2
+5
+9
+8
+7
+3
+6
+6
+1
+6
+2
+1
+0
+1
+0
+5
+3
+7
+1
+2
+1
+3
+1
+0
+1
+5
+9
+9
+2
+3
+7
+7
+3
+1
+6
+5
+4
+2
+0
+4
+9
+1
+4
+7
+7
+5
+6
+6
+0
+8
+0
+2
+5
+6
+5
+3
+0
+4
+0
+7
+6
+1
+4
+3
+9
+2
+5
+9
+1
+4
+6
+7
+9
+9
+2
+2
+7
+0
+0
+5
+4
+9
+4
+7
+2
+1
+7
+0
+9
+1
+3
+9
+2
+7
+2
+3
+5
+0
+3
+5
+4
+2
+6
+6
+5
+2
+3
+7
+9
+2
+2
+0
+7
+1
+3
+4
+9
+3
+5
+9
+4
+6
+7
+7
+1
+7
+9
+1
+7
+7
+3
+0
+2
+4
+0
+7
+1
+4
+5
+4
+4
+7
+2
+5
+0
+3
+1
+6
+3
+9
+1
+5
+1
+3
+7
+0
+9
+4
+6
+4
+4
+1
+4
+5
+2
+0
+8
+8
+8
+8
+8
+3
+8
+6
+8
+8
+8
+8
+8
+3
+0
+8
+5
+2
+6
+6
+3
+5
+7
+9
+0
+9
+2
+5
+5
+0
+1
+9
+3
+8
+7
+2
+5
+3
+8
+8
+2
+5
+8
+0
+9
+7
+8
+1
+0
+5
+8
+7
+8
+3
+8
+4
+8
+6
+0
+8
+9
+5
+6
+6
+4
+7
+2
+9
+8
+5
+3
+4
+8
+8
+9
+2
+2
+0
+5
+8
+0
+4
+9
+8
+4
+3
+5
+7
+8
+1
+9
+9
+6
+3
+4
+6
+3
+1
+1
+7
+5
+1
+4
+2
+9
+6
+9
+6
+1
+7
+6
+0
+3
+6
+1
+9
+6
+2
+6
+0
+5
+0
+5
+1
+1
+5
+2
+7
+9
+1
+2
+6
+4
+6
+0
+2
+1
+7
+3
+9
+2
+1
+7
+7
+9
+4
+4
+9
+4
+2
+2
+1
+9
+7
+0
+4
+7
+1
+4
+3
+0
+3
+3
+4
+5
+4
+4
+2
+7
+3
+0
+7
+2
+6
+6
+5
+9
+9
+3
+1
+6
+2
+2
+4
+5
+9
+1
+6
+4
+1
+0
+1
+1
+5
+3
+0
+9
+5
+2
+4
+7
+4
+3
+1
+7
+6
+7
+2
+2
+4
+7
+4
+9
+6
+5
+3
+6
+5
+3
+6
+9
+7
+0
+9
+5
+3
+1
+5
+6
+1
+6
+0
+7
+7
+6
+2
+1
+9
+1
+5
+2
+3
+6
+4
+9
+4
+4
+9
+4
+3
+3
+1
+9
+9
+7
+9
+4
+1
+5
+3
+3
+5
+2
+4
+1
+4
+4
+3
+4
+9
+5
+0
+2
+1
+0
+0
+3
+0
+5
+1
+6
+2
+7
+7
+3
+9
+1
+6
+8
+8
+0
+5
+7
+6
+3
+8
+8
+8
+6
+2
+8
+8
+0
+5
+8
+8
+8
+8
+8
+8
+8
+8
+8
+2
+8
+8
+8
+8
+3
+8
+3
+2
+1
+4
+9
+2
+5
+0
+3
+5
+7
+1
+6
+9
+6
+4
+1
+0
+2
+5
+6
+9
+1
+2
+7
+1
+6
+0
+2
+9
+3
+5
+6
+6
+4
+5
+7
+9
+6
+3
+5
+6
+9
+4
+0
+9
+2
+3
+3
+4
+4
+2
+7
+7
+7
+2
+3
+0
+8
+8
+5
+9
+0
+3
+7
+1
+0
+4
+0
+4
+4
+0
+1
+0
+3
+5
+5
+6
+2
+3
+4
+1
+9
+5
+5
+9
+0
+2
+0
+4
+6
+6
+4
+0
+6
+5
+0
+2
+7
+7
+1
+6
+1
+6
+5
+3
+2
+9
+3
+7
+2
+1
+7
+3
+6
+9
+1
+5
+6
+2
+2
+3
+1
+9
+7
+1
+5
+0
+2
+3
+3
+7
+0
+6
+7
+3
+6
+2
+6
+0
+0
+0
+9
+4
+6
+9
+6
+4
+5
+0
+9
+7
+9
+1
+5
+2
+2
+5
+9
+0
+2
+3
+7
+7
+3
+2
+9
+5
+5
+3
+4
+4
+3
+7
+1
+9
+5
+7
+1
+7
+4
+1
+9
+0
+0
+0
+3
+2
+3
+4
+4
+9
+8
+1
+8
+3
+8
+2
+0
+8
+1
+5
+8
+6
+7
+8
+8
+7
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+5
+3
+8
+7
+8
+8
+6
+5
+6
+6
+1
+2
+3
+9
+7
+7
+7
+7
+9
+3
+2
+1
+8
+4
+0
+1
+0
+5
+3
+2
+8
+7
+1
+2
+5
+1
+4
+1
+6
+4
+7
+6
+5
+0
+3
+6
+8
+5
+9
+1
+7
+2
+3
+0
+1
+8
+7
+9
+3
+4
+1
+0
+4
+1
+2
+9
+7
+5
+8
+4
+9
+5
+9
+9
+2
+3
+0
+0
+9
+7
+4
+9
+6
+6
+5
+5
+5
+0
+1
+9
+4
+3
+3
+1
+9
+7
+6
+5
+1
+0
+7
+7
+3
+9
+9
+1
+6
+6
+6
+6
+1
+9
+0
+7
+0
+1
+2
+3
+3
+1
+6
+4
+0
+4
+4
+0
+4
+0
+5
+7
+2
+5
+0
+4
+2
+9
+0
+6
+1
+7
+1
+5
+5
+4
+3
+1
+4
+5
+2
+1
+5
+9
+2
+1
+7
+7
+0
+3
+6
+6
+1
+2
+5
+1
+6
+2
+1
+4
+4
+2
+5
+1
+5
+3
+7
+0
+7
+1
+9
+9
+4
+5
+3
+5
+1
+5
+9
+3
+0
+9
+0
+7
+2
+0
+9
+5
+2
+3
+0
+0
+5
+2
+7
+7
+7
+1
+2
+6
+6
+0
+0
+0
+5
+6
+6
+2
+1
+0
+9
+9
+6
+4
+3
+4
+3
+7
+1
+9
+0
+0
+8
+8
+8
+8
+5
+8
+8
+8
+2
+8
+9
+8
+3
+4
+4
+8
+7
+5
+3
+5
+7
+9
+0
+7
+1
+3
+2
+2
+9
+6
+9
+4
+7
+8
+9
+2
+1
+8
+0
+5
+0
+6
+9
+9
+6
+2
+5
+1
+4
+7
+9
+1
+3
+8
+7
+6
+8
+8
+1
+5
+0
+1
+8
+8
+5
+3
+0
+2
+0
+5
+0
+2
+7
+6
+3
+1
+3
+4
+0
+6
+9
+3
+4
+9
+6
+2
+1
+6
+9
+3
+6
+9
+5
+0
+7
+4
+6
+9
+3
+4
+3
+4
+4
+2
+4
+9
+5
+3
+3
+0
+1
+5
+0
+9
+1
+0
+3
+1
+2
+5
+7
+9
+0
+7
+4
+5
+2
+0
+9
+1
+5
+0
+7
+0
+9
+7
+1
+9
+1
+4
+6
+6
+9
+0
+9
+2
+5
+3
+7
+7
+5
+0
+6
+5
+6
+6
+3
+1
+1
+4
+7
+7
+7
+5
+1
+3
+6
+6
+2
+1
+5
+6
+4
+3
+9
+9
+4
+0
+6
+1
+1
+0
+9
+4
+5
+4
+1
+3
+4
+3
+9
+1
+4
+0
+2
+3
+6
+7
+0
+4
+0
+6
+4
+5
+5
+3
+3
+6
+2
+4
+6
+6
+5
+9
+3
+7
+4
+2
+7
+4
+0
+4
+3
+0
+0
+8
+9
+8
+8
+8
+7
+8
+3
+8
+9
+2
+2
+5
+8
+4
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+6
+8
+5
+1
+2
+9
+8
+5
+8
+3
+1
+0
+1
+6
+2
+7
+6
+3
+6
+7
+4
+8
+4
+2
+6
+6
+3
+5
+9
+9
+8
+4
+1
+8
+0
+6
+2
+5
+1
+4
+4
+2
+9
+1
+5
+9
+7
+5
+7
+4
+4
+2
+7
+1
+1
+0
+8
+5
+5
+4
+3
+9
+7
+7
+2
+0
+7
+6
+7
+6
+6
+5
+2
+9
+3
+4
+3
+5
+0
+7
+9
+9
+7
+7
+0
+0
+2
+0
+7
+3
+3
+1
+8
+1
+7
+2
+9
+5
+3
+3
+7
+5
+0
+4
+2
+9
+4
+3
+5
+2
+7
+5
+0
+6
+2
+0
+5
+7
+2
+6
+4
+9
+4
+2
+6
+6
+1
+7
+5
+4
+5
+1
+2
+1
+3
+6
+2
+4
+1
+4
+4
+5
+4
+0
+7
+9
+2
+3
+6
+0
+9
+0
+5
+9
+1
+2
+3
+4
+3
+4
+7
+7
+1
+3
+2
+0
+1
+0
+2
+2
+4
+1
+5
+7
+9
+9
+0
+1
+2
+3
+3
+4
+9
+2
+4
+0
+6
+7
+1
+3
+9
+9
+5
+6
+9
+2
+0
+0
+3
+1
+5
+4
+9
+7
+2
+3
+3
+9
+7
+7
+4
+3
+9
+9
+3
+1
+1
+0
+2
+6
+4
+9
+4
+2
+6
+5
+8
+8
+8
+8
+8
+8
+8
+8
+5
+9
+8
+8
+8
+4
+4
+8
+6
+6
+5
+6
+2
+5
+6
+5
+2
+7
+0
+3
+0
+2
+5
+4
+5
+1
+6
+8
+7
+7
+8
+8
+1
+9
+2
+5
+4
+3
+8
+0
+4
+9
+0
+2
+0
+8
+8
+8
+8
+9
+7
+7
+6
+3
+0
+5
+3
+4
+4
+5
+4
+3
+9
+7
+6
+0
+2
+4
+6
+5
+9
+3
+8
+0
+5
+1
+7
+4
+6
+6
+3
+9
+1
+0
+0
+1
+9
+4
+1
+2
+1
+4
+9
+4
+4
+5
+4
+6
+2
+1
+7
+3
+5
+0
+5
+9
+7
+2
+6
+6
+1
+6
+2
+1
+4
+5
+2
+3
+3
+9
+3
+2
+4
+6
+9
+3
+5
+1
+3
+7
+2
+4
+9
+9
+2
+2
+0
+0
+1
+5
+9
+1
+3
+2
+3
+7
+5
+0
+9
+0
+7
+5
+0
+1
+2
+4
+9
+9
+2
+5
+1
+4
+0
+2
+0
+6
+5
+6
+5
+1
+0
+2
+0
+6
+9
+1
+7
+4
+6
+7
+4
+9
+1
+3
+8
+8
+8
+8
+7
+8
+8
+8
+8
+3
+8
+8
+8
+4
+8
+8
+6
+0
+3
+1
+7
+7
+0
+7
+0
+2
+1
+0
+9
+5
+2
+4
+2
+9
+5
+8
+6
+6
+8
+6
+8
+9
+3
+7
+8
+8
+5
+8
+8
+8
+8
+8
+8
+8
+0
+8
+8
+7
+8
+8
+8
+8
+8
+8
+0
+0
+3
+8
+5
+7
+5
+1
+8
+3
+0
+0
+3
+4
+9
+8
+8
+5
+2
+0
+4
+0
+8
+2
+8
+3
+7
+2
+2
+4
+4
+0
+7
+1
+0
+4
+0
+2
+7
+5
+1
+6
+6
+3
+3
+1
+5
+4
+6
+6
+2
+2
+3
+5
+9
+1
+0
+4
+4
+5
+2
+0
+1
+8
+6
+2
+6
+7
+5
+6
+3
+9
+9
+5
+2
+3
+7
+7
+3
+1
+0
+5
+4
+1
+4
+0
+9
+9
+2
+9
+1
+3
+6
+1
+9
+9
+1
+6
+4
+3
+2
+5
+7
+7
+4
+2
+9
+3
+3
+0
+5
+4
+0
+3
+2
+4
+7
+4
+5
+7
+4
+1
+9
+3
+0
+9
+0
+4
+7
+1
+9
+9
+5
+0
+3
+4
+1
+2
+4
+9
+4
+3
+6
+5
+7
+7
+9
+3
+6
+6
+7
+0
+5
+0
+6
+2
+1
+5
+3
+2
+2
+1
+7
+9
+6
+3
+6
+6
+1
+2
+1
+9
+7
+1
+5
+7
+5
+0
+7
+4
+3
+3
+4
+2
+1
+4
+0
+0
+7
+7
+1
+7
+2
+2
+9
+9
+1
+2
+1
+3
+9
+2
+4
+9
+0
+6
+7
+5
+9
+5
+0
+1
+0
+3
+1
+2
+5
+6
+1
+6
+2
+1
+0
+7
+8
+8
+8
+7
+8
+8
+8
+8
+2
+8
+0
+8
+5
+4
+8
+8
+7
+2
+0
+7
+0
+3
+5
+9
+3
+5
+2
+5
+6
+7
+0
+9
+8
+8
+8
+2
+9
+6
+8
+0
+6
+0
+6
+6
+9
+2
+7
+7
+4
+8
+8
+6
+8
+8
+8
+4
+5
+8
+2
+8
+9
+0
+8
+3
+0
+3
+4
+1
+4
+9
+8
+5
+1
+3
+3
+4
+0
+9
+5
+9
+5
+1
+3
+0
+9
+0
+5
+3
+4
+7
+2
+5
+6
+6
+1
+6
+2
+3
+0
+5
+2
+7
+1
+4
+6
+6
+4
+1
+3
+2
+0
+1
+8
+3
+3
+1
+6
+9
+6
+6
+5
+3
+1
+7
+3
+1
+4
+2
+1
+5
+3
+9
+4
+1
+5
+2
+6
+3
+0
+9
+0
+5
+6
+6
+7
+7
+3
+0
+6
+6
+6
+6
+5
+1
+3
+9
+7
+7
+2
+3
+9
+6
+6
+4
+0
+5
+6
+1
+9
+0
+9
+5
+1
+2
+7
+7
+4
+2
+7
+9
+5
+1
+0
+4
+0
+4
+4
+9
+4
+7
+2
+7
+8
+5
+8
+8
+8
+8
+8
+8
+2
+9
+8
+8
+8
+4
+8
+6
+9
+2
+5
+0
+3
+6
+4
+1
+9
+7
+6
+6
+3
+1
+1
+0
+5
+6
+8
+0
+1
+7
+6
+6
+8
+9
+7
+5
+5
+3
+3
+1
+4
+9
+8
+1
+5
+8
+3
+4
+7
+0
+4
+7
+8
+1
+3
+8
+4
+5
+2
+3
+6
+6
+3
+6
+5
+7
+6
+2
+2
+5
+7
+9
+8
+4
+5
+3
+9
+5
+1
+0
+8
+0
+8
+4
+9
+4
+4
+7
+5
+0
+2
+4
+9
+3
+0
+2
+0
+8
+7
+7
+1
+9
+1
+4
+0
+2
+1
+3
+5
+9
+3
+4
+7
+7
+0
+7
+0
+3
+6
+5
+3
+1
+4
+0
+7
+6
+7
+2
+5
+6
+9
+6
+2
+5
+4
+0
+6
+4
+0
+6
+0
+5
+6
+1
+3
+0
+7
+6
+9
+9
+1
+4
+5
+7
+9
+4
+1
+4
+7
+2
+4
+0
+9
+5
+5
+2
+5
+4
+3
+0
+9
+1
+5
+9
+7
+3
+3
+4
+1
+0
+6
+0
+2
+5
+1
+9
+6
+6
+7
+7
+2
+0
+5
+4
+7
+1
+4
+5
+1
+2
+3
+9
+5
+9
+4
+5
+1
+5
+3
+9
+7
+7
+5
+6
+4
+0
+0
+7
+3
+0
+0
+4
+2
+7
+4
+9
+3
+2
+0
+6
+6
+6
+2
+9
+1
+5
+6
+4
+9
+3
+6
+2
+6
+6
+1
+3
+9
+5
+6
+1
+0
+7
+6
+6
+6
+9
+1
+4
+4
+2
+2
+5
+9
+9
+2
+7
+3
+7
+4
+5
+7
+1
+0
+2
+3
+4
+5
+4
+1
+9
+8
+0
+7
+8
+1
+8
+5
+8
+8
+8
+8
+2
+9
+0
+8
+1
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+6
+8
+8
+1
+8
+8
+1
+7
+9
+8
+3
+8
+8
+5
+5
+8
+2
+9
+3
+0
+8
+2
+5
+3
+9
+2
+8
+0
+7
+4
+2
+6
+9
+8
+5
+2
+6
+0
+5
+4
+7
+7
+6
+6
+5
+1
+6
+5
+2
+4
+7
+7
+4
+2
+7
+6
+6
+2
+2
+1
+4
+0
+4
+2
+5
+3
+1
+2
+8
+4
+9
+1
+6
+9
+1
+7
+0
+5
+0
+4
+4
+9
+4
+3
+7
+7
+0
+1
+5
+9
+2
+5
+3
+1
+9
+2
+0
+9
+7
+2
+1
+6
+9
+9
+4
+0
+1
+0
+5
+2
+3
+5
+7
+6
+6
+3
+6
+2
+9
+6
+0
+1
+2
+3
+6
+6
+4
+7
+5
+7
+4
+1
+3
+4
+5
+2
+0
+9
+0
+5
+4
+3
+4
+7
+9
+1
+6
+6
+0
+7
+3
+0
+2
+9
+2
+3
+1
+3
+6
+1
+6
+6
+7
+0
+7
+3
+4
+0
+3
+5
+6
+2
+0
+6
+7
+3
+5
+7
+0
+0
+1
+5
+9
+4
+3
+9
+4
+1
+6
+5
+9
+7
+0
+2
+0
+4
+4
+0
+8
+9
+8
+8
+3
+7
+8
+8
+4
+9
+8
+8
+5
+1
+8
+0
+8
+8
+8
+8
+8
+8
+8
+8
+8
+6
+8
+7
+8
+8
+8
+8
+8
+9
+8
+3
+1
+6
+7
+7
+0
+9
+5
+3
+3
+4
+9
+1
+6
+0
+2
+6
+4
+8
+6
+7
+5
+9
+8
+0
+2
+1
+8
+1
+1
+3
+4
+8
+2
+7
+0
+9
+6
+6
+7
+5
+5
+2
+6
+6
+1
+0
+8
+4
+5
+4
+1
+6
+7
+1
+7
+7
+3
+8
+8
+4
+0
+6
+6
+6
+2
+9
+7
+7
+1
+4
+0
+3
+0
+5
+3
+0
+8
+5
+1
+3
+0
+7
+2
+5
+5
+0
+5
+3
+1
+6
+5
+2
+5
+7
+9
+1
+1
+3
+3
+0
+4
+2
+9
+3
+5
+3
+6
+6
+7
+1
+2
+4
+6
+4
+4
+2
+1
+5
+9
+0
+2
+0
+3
+2
+6
+0
+7
+5
+1
+2
+6
+4
+3
+4
+4
+0
+7
+5
+2
+1
+7
+4
+9
+0
+1
+0
+2
+5
+3
+1
+9
+2
+2
+1
+4
+0
+1
+0
+4
+2
+4
+3
+9
+6
+3
+9
+0
+1
+0
+4
+9
+0
+1
+2
+6
+0
+5
+0
+1
+7
+4
+1
+2
+1
+1
+3
+0
+5
+3
+5
+0
+2
+0
+3
+9
+3
+2
+4
+5
+9
+7
+5
+0
+3
+4
+2
+5
+7
+4
+1
+9
+4
+6
+6
+2
+0
+1
+7
+5
+6
+8
+8
+8
+8
+6
+8
+8
+8
+8
+8
+8
+4
+8
+8
+4
+8
+0
+1
+6
+6
+5
+4
+9
+9
+1
+5
+0
+2
+7
+7
+9
+9
+8
+3
+8
+0
+1
+0
+1
+9
+7
+7
+5
+7
+9
+2
+8
+1
+8
+8
+8
+8
+8
+8
+8
+8
+8
+3
+2
+8
+9
+1
+7
+6
+1
+8
+2
+9
+0
+0
+5
+2
+2
+3
+3
+9
+2
+4
+0
+0
+8
+4
+3
+7
+4
+2
+1
+0
+8
+1
+3
+1
+6
+6
+2
+5
+8
+5
+9
+4
+3
+4
+4
+2
+9
+6
+5
+9
+2
+5
+7
+6
+0
+3
+1
+9
+6
+2
+8
+6
+7
+3
+4
+9
+1
+8
+2
+7
+0
+6
+4
+6
+4
+0
+6
+2
+9
+3
+0
+7
+5
+4
+4
+0
+9
+1
+0
+9
+0
+7
+5
+0
+9
+5
+2
+7
+3
+1
+0
+5
+9
+9
+9
+4
+1
+7
+3
+0
+2
+9
+5
+3
+6
+3
+3
+6
+4
+2
+5
+3
+1
+6
+1
+4
+9
+9
+7
+6
+4
+0
+2
+1
+4
+5
+7
+3
+3
+0
+9
+9
+5
+9
+5
+2
+6
+7
+5
+9
+7
+4
+0
+7
+3
+2
+1
+0
+6
+1
+6
+5
+3
+4
+4
+6
+8
+8
+2
+8
+8
+8
+6
+0
+4
+0
+8
+2
+9
+8
+7
+7
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+7
+5
+3
+8
+0
+5
+2
+1
+9
+3
+3
+5
+7
+8
+0
+7
+2
+1
+5
+9
+5
+4
+4
+8
+4
+3
+3
+9
+6
+6
+8
+4
+9
+3
+6
+6
+3
+7
+0
+4
+0
+6
+4
+2
+4
+5
+6
+6
+2
+9
+6
+4
+3
+6
+8
+6
+9
+2
+0
+4
+0
+4
+1
+7
+4
+1
+2
+1
+9
+5
+0
+9
+7
+3
+2
+4
+9
+7
+6
+6
+4
+3
+5
+2
+6
+6
+9
+9
+2
+3
+1
+6
+9
+1
+9
+5
+5
+3
+7
+8
+9
+0
+6
+6
+5
+7
+2
+3
+9
+9
+7
+0
+0
+0
+1
+2
+9
+5
+1
+4
+0
+4
+4
+1
+7
+2
+5
+7
+1
+6
+1
+3
+4
+9
+3
+1
+7
+3
+2
+4
+5
+3
+4
+2
+4
+1
+5
+6
+2
+9
+3
+1
+6
+7
+0
+0
+1
+2
+3
+5
+5
+4
+4
+3
+6
+7
+2
+6
+3
+4
+0
+6
+0
+5
+3
+2
+3
+0
+9
+1
+2
+5
+3
+5
+1
+2
+9
+4
+9
+2
+1
+9
+0
+1
+9
+1
+1
+6
+5
+7
+7
+7
+0
+6
+0
+3
+2
+1
+4
+9
+5
+2
+4
+6
+3
+2
+9
+9
+5
+4
+2
+3
+4
+5
+0
+9
+4
+0
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+9
+4
+8
+8
+4
+5
+7
+5
+1
+2
+3
+1
+7
+7
+2
+6
+5
+6
+3
+2
+6
+4
+8
+8
+5
+7
+6
+6
+2
+0
+0
+4
+2
+3
+4
+7
+3
+2
+8
+7
+6
+2
+8
+8
+8
+8
+8
+8
+9
+0
+8
+0
+8
+8
+0
+4
+4
+9
+1
+3
+2
+8
+7
+1
+0
+9
+0
+3
+7
+5
+2
+5
+7
+9
+2
+4
+3
+8
+5
+2
+1
+9
+7
+1
+6
+4
+1
+2
+5
+4
+3
+4
+4
+5
+4
+9
+0
+1
+5
+7
+2
+4
+7
+7
+0
+3
+0
+8
+7
+2
+2
+5
+4
+3
+6
+6
+3
+8
+9
+2
+7
+5
+5
+3
+9
+9
+6
+6
+2
+4
+7
+4
+2
+9
+0
+5
+1
+7
+6
+3
+0
+2
+5
+9
+6
+0
+2
+3
+9
+9
+6
+0
+6
+4
+9
+5
+6
+3
+3
+7
+1
+0
+9
+0
+7
+3
+3
+1
+0
+0
+2
+0
+5
+2
+3
+4
+4
+5
+4
+2
+7
+7
+3
+2
+3
+5
+1
+7
+1
+3
+3
+1
+3
+7
+6
+4
+4
+1
+3
+5
+1
+2
+9
+6
+0
+3
+5
+6
+6
+6
+9
+1
+6
+3
+1
+5
+9
+8
+8
+2
+8
+8
+4
+8
+9
+1
+6
+5
+8
+6
+8
+8
+8
+8
+8
+0
+8
+8
+8
+8
+9
+2
+8
+8
+8
+0
+5
+6
+0
+7
+0
+2
+6
+6
+8
+0
+3
+9
+7
+7
+0
+3
+7
+4
+2
+7
+4
+1
+0
+3
+0
+5
+9
+4
+2
+7
+8
+3
+0
+5
+3
+4
+5
+2
+4
+3
+9
+3
+5
+0
+0
+5
+7
+7
+0
+1
+2
+9
+8
+0
+8
+2
+6
+6
+3
+9
+7
+6
+5
+7
+5
+2
+0
+0
+6
+0
+1
+5
+7
+1
+6
+5
+3
+4
+2
+0
+9
+3
+4
+1
+5
+4
+5
+2
+9
+7
+1
+9
+2
+1
+8
+1
+1
+5
+0
+0
+3
+0
+9
+9
+5
+2
+6
+1
+3
+5
+7
+7
+6
+3
+7
+4
+6
+4
+1
+9
+4
+0
+3
+2
+7
+7
+5
+2
+2
+1
+6
+3
+9
+2
+0
+4
+0
+7
+4
+3
+4
+0
+1
+9
+0
+4
+1
+0
+9
+1
+2
+9
+7
+7
+0
+2
+6
+6
+7
+5
+0
+5
+0
+1
+9
+9
+3
+7
+5
+2
+7
+3
+9
+9
+6
+6
+4
+1
+5
+3
+0
+5
+2
+6
+7
+0
+7
+7
+9
+1
+3
+9
+2
+6
+5
+6
+7
+3
+7
+4
+0
+0
+2
+5
+5
+3
+2
+1
+0
+4
+2
+1
+5
+3
+3
+7
+2
+5
+1
+2
+2
+1
+4
+5
+6
+8
+8
+8
+8
+3
+8
+8
+8
+0
+8
+8
+8
+4
+4
+8
+9
+0
+5
+3
+3
+5
+1
+5
+7
+1
+2
+0
+5
+0
+3
+4
+3
+9
+8
+8
+7
+7
+5
+1
+3
+9
+0
+5
+0
+6
+1
+8
+8
+9
+8
+0
+8
+1
+8
+8
+6
+9
+7
+6
+1
+8
+8
+5
+7
+4
+4
+1
+0
+6
+7
+6
+5
+2
+1
+6
+8
+2
+0
+3
+3
+1
+6
+6
+8
+5
+0
+7
+0
+9
+2
+2
+5
+0
+9
+3
+2
+0
+3
+7
+2
+2
+5
+4
+3
+4
+3
+0
+4
+0
+9
+9
+7
+7
+7
+1
+5
+0
+9
+3
+3
+6
+1
+2
+6
+1
+6
+2
+1
+0
+6
+2
+4
+9
+7
+7
+2
+2
+9
+1
+1
+0
+4
+3
+5
+2
+5
+0
+7
+9
+1
+3
+3
+1
+2
+1
+6
+9
+2
+6
+7
+3
+9
+0
+0
+9
+4
+2
+6
+5
+9
+5
+6
+7
+1
+6
+4
+6
+9
+5
+6
+1
+7
+0
+0
+3
+5
+6
+4
+9
+2
+5
+6
+4
+7
+9
+3
+9
+0
+5
+0
+3
+1
+9
+7
+4
+4
+7
+0
+2
+7
+7
+3
+5
+4
+5
+1
+3
+0
+9
+3
+7
+2
+4
+9
+3
+9
+2
+1
+0
+5
+4
+2
+5
+4
+3
+6
+2
+6
+1
+4
+2
+0
+3
+0
+6
+2
+4
+6
+0
+1
+3
+3
+1
+7
+7
+1
+9
+2
+8
+7
+1
+0
+7
+2
+9
+8
+1
+2
+6
+9
+6
+0
+4
+4
+8
+6
+7
+1
+8
+5
+1
+0
+4
+0
+5
+4
+8
+7
+6
+5
+3
+6
+5
+6
+2
+4
+9
+6
+3
+2
+7
+3
+4
+5
+7
+1
+6
+3
+2
+5
+0
+0
+0
+4
+3
+1
+7
+9
+8
+5
+4
+7
+7
+5
+3
+3
+9
+1
+5
+1
+4
+2
+6
+3
+5
+7
+0
+4
+7
+3
+4
+3
+9
+5
+6
+5
+6
+0
+0
+3
+9
+3
+5
+5
+4
+9
+4
+4
+2
+3
+7
+0
+6
+9
+2
+7
+7
+5
+2
+6
+1
+0
+3
+3
+9
+7
+4
+1
+5
+7
+1
+2
+7
+0
+4
+9
+9
+5
+6
+2
+4
+6
+4
+0
+9
+0
+7
+3
+5
+6
+7
+9
+6
+0
+3
+1
+6
+5
+1
+9
+4
+7
+3
+0
+7
+3
+1
+5
+9
+6
+5
+4
+1
+3
+0
+9
+2
+7
+3
+1
+3
+3
+0
+7
+4
+9
+1
+5
+1
+3
+5
+9
+9
+6
+7
+7
+6
+4
+0
+2
+5
+5
+7
+5
+4
+1
+7
+3
+0
+2
+1
+6
+5
+9
+5
+4
+0
+4
+0
+6
+3
+9
+7
+6
+4
+6
+4
+7
+0
+8
+9
+6
+6
+1
+5
+8
+8
+8
+9
+7
+2
+2
+8
+0
+1
+2
+8
+8
+8
+8
+8
+8
+8
+7
+9
+1
+8
+8
+1
+8
+8
+6
+6
+3
+5
+9
+8
+6
+8
+7
+7
+2
+1
+9
+8
+7
+2
+8
+8
+8
+2
+8
+8
+1
+5
+0
+1
+3
+8
+9
+2
+7
+7
+5
+4
+4
+8
+4
+9
+2
+1
+1
+3
+7
+7
+6
+9
+1
+2
+0
+3
+1
+4
+2
+1
+5
+9
+7
+5
+6
+6
+0
+2
+6
+4
+4
+3
+2
+5
+7
+7
+2
+6
+6
+4
+5
+3
+4
+9
+0
+0
+2
+1
+6
+6
+2
+9
+0
+5
+5
+0
+7
+4
+3
+2
+4
+9
+7
+7
+9
+3
+1
+5
+7
+5
+0
+1
+9
+2
+5
+9
+3
+2
+2
+0
+5
+1
+2
+4
+4
+7
+4
+5
+9
+3
+0
+1
+3
+6
+1
+9
+6
+4
+7
+7
+4
+7
+0
+9
+5
+1
+1
+5
+3
+5
+9
+5
+1
+3
+3
+7
+1
+2
+2
+9
+7
+7
+4
+6
+6
+6
+0
+2
+4
+0
+4
+3
+9
+7
+6
+6
+0
+5
+5
+3
+9
+0
+9
+6
+1
+2
+7
+1
+3
+7
+2
+5
+6
+3
+1
+2
+0
+4
+3
+2
+6
+6
+5
+3
+9
+0
+3
+0
+5
+2
+4
+5
+9
+5
+4
+7
+7
+2
+2
+3
+7
+4
+2
+4
+4
+0
+0
+6
+5
+7
+8
+0
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+7
+4
+4
+1
+3
+9
+7
+1
+6
+0
+5
+6
+2
+5
+1
+6
+7
+1
+9
+3
+1
+3
+3
+7
+2
+0
+9
+5
+5
+3
+3
+1
+1
+7
+5
+0
+5
+7
+0
+4
+0
+4
+4
+3
+4
+1
+3
+5
+5
+6
+9
+4
+4
+3
+7
+1
+3
+6
+9
+1
+6
+0
+6
+6
+4
+1
+1
+9
+6
+3
+1
+7
+4
+1
+2
+1
+1
+3
+5
+0
+3
+5
+9
+2
+2
+5
+6
+3
+3
+2
+9
+5
+7
+2
+1
+3
+0
+1
+5
+9
+5
+1
+2
+4
+3
+0
+2
+9
+1
+7
+1
+3
+6
+6
+7
+6
+4
+2
+0
+3
+0
+2
+3
+4
+6
+2
+4
+7
+9
+3
+0
+6
+1
+4
+2
+5
+9
+6
+2
+6
+7
+1
+5
+2
+9
+5
+3
+1
+1
+4
+5
+9
+0
+1
+3
+5
+2
+7
+9
+1
+6
+4
+0
+7
+5
+2
+9
+3
+6
+6
+0
+6
+0
+1
+2
+9
+7
+0
+7
+7
+9
+6
+9
+2
+5
+3
+6
+1
+9
+5
+7
+0
+4
+0
+1
+0
+4
+5
+1
+9
+5
+1
+3
+1
+7
+7
+2
+9
+1
+3
+3
+0
+8
+8
+4
+8
+4
+8
+8
+8
+8
+8
+8
+8
+6
+2
+8
+3
+3
+1
+5
+4
+7
+4
+4
+0
+3
+0
+6
+7
+5
+3
+6
+4
+8
+9
+8
+8
+5
+6
+0
+7
+0
+9
+3
+8
+4
+2
+8
+3
+8
+5
+8
+8
+7
+8
+8
+3
+8
+9
+2
+8
+0
+5
+8
+3
+1
+8
+5
+2
+6
+5
+0
+3
+0
+6
+7
+1
+2
+4
+5
+3
+3
+8
+4
+6
+9
+2
+5
+9
+3
+8
+0
+7
+9
+8
+2
+3
+6
+1
+3
+4
+7
+4
+4
+2
+2
+5
+3
+5
+9
+9
+1
+5
+4
+5
+1
+5
+0
+7
+7
+4
+5
+4
+3
+8
+1
+9
+6
+6
+7
+7
+5
+1
+4
+9
+0
+2
+6
+0
+9
+6
+3
+4
+4
+6
+5
+3
+3
+1
+6
+9
+7
+6
+1
+3
+3
+0
+5
+0
+2
+4
+0
+6
+7
+2
+5
+9
+1
+4
+2
+1
+9
+3
+0
+7
+7
+5
+7
+2
+9
+0
+3
+9
+1
+4
+5
+4
+4
+2
+3
+6
+2
+1
+1
+9
+2
+6
+3
+5
+7
+4
+9
+9
+0
+1
+5
+7
+5
+0
+2
+9
+4
+9
+4
+2
+5
+7
+9
+5
+3
+4
+3
+4
+4
+4
+9
+9
+0
+5
+5
+4
+9
+1
+4
+0
+1
+2
+6
+7
+1
+6
+2
+7
+1
+7
+3
+6
+9
+1
+0
+9
+6
+3
+1
+0
+9
+6
+0
+6
+2
+1
+6
+3
+6
+9
+2
+7
+1
+2
+2
+3
+7
+9
+5
+4
+7
+0
+4
+2
+3
+6
+1
+9
+1
+4
+7
+7
+4
+0
+3
+8
+2
+5
+8
+4
+8
+8
+3
+7
+8
+8
+9
+8
+8
+4
+8
+8
+1
+8
+8
+8
+8
+8
+6
+0
+8
+8
+8
+8
+7
+8
+1
+0
+1
+5
+9
+9
+2
+7
+2
+4
+4
+0
+4
+3
+3
+2
+2
+4
+5
+0
+2
+9
+1
+7
+6
+1
+8
+1
+9
+9
+3
+0
+7
+1
+9
+7
+0
+6
+2
+1
+3
+6
+9
+5
+5
+7
+1
+4
+6
+7
+6
+4
+5
+1
+0
+1
+0
+2
+9
+0
+1
+3
+1
+7
+4
+5
+7
+1
+1
+9
+6
+4
+3
+7
+4
+9
+7
+5
+7
+3
+0
+1
+5
+7
+4
+2
+3
+5
+1
+2
+0
+4
+0
+4
+5
+6
+5
+5
+3
+0
+0
+0
+1
+2
+6
+7
+3
+6
+5
+6
+7
+0
+2
+6
+9
+9
+5
+2
+6
+3
+7
+0
+9
+9
+4
+9
+7
+7
+1
+5
+7
+0
+0
+0
+9
+3
+5
+6
+3
+1
+7
+7
+6
+0
+4
+9
+5
+2
+6
+5
+1
+6
+2
+1
+6
+1
+7
+2
+9
+3
+8
+3
+4
+8
+4
+8
+8
+8
+8
+3
+2
+8
+8
+8
+8
+7
+0
+0
+1
+2
+5
+1
+4
+9
+4
+2
+3
+5
+7
+2
+7
+9
+0
+5
+8
+1
+9
+8
+2
+9
+5
+4
+0
+7
+0
+6
+8
+2
+8
+1
+5
+8
+0
+5
+8
+8
+1
+7
+6
+6
+9
+2
+0
+8
+5
+8
+2
+3
+9
+7
+6
+6
+0
+0
+6
+5
+9
+9
+8
+2
+2
+0
+6
+4
+2
+4
+4
+9
+4
+2
+7
+7
+9
+2
+8
+4
+1
+2
+1
+4
+6
+4
+4
+0
+9
+7
+6
+3
+3
+5
+2
+2
+1
+0
+6
+9
+3
+5
+6
+2
+2
+1
+4
+9
+2
+0
+7
+8
+9
+2
+4
+3
+4
+7
+3
+1
+9
+3
+7
+4
+0
+4
+2
+2
+9
+3
+1
+5
+5
+0
+4
+2
+7
+5
+7
+7
+1
+6
+6
+0
+9
+2
+0
+1
+7
+3
+7
+7
+5
+9
+6
+6
+4
+1
+0
+2
+6
+6
+5
+2
+7
+7
+3
+4
+1
+9
+4
+3
+5
+3
+3
+1
+3
+2
+6
+6
+4
+3
+9
+6
+3
+1
+2
+4
+5
+4
+9
+2
+0
+9
+7
+5
+1
+3
+7
+0
+3
+9
+0
+9
+6
+6
+3
+5
+1
+0
+6
+6
+7
+9
+4
+5
+3
+4
+0
+1
+9
+9
+2
+4
+0
+7
+2
+0
+9
+3
+3
+2
+2
+1
+7
+2
+5
+3
+3
+0
+3
+7
+0
+0
+0
+0
+7
+3
+3
+5
+2
+5
+6
+9
+1
+0
+3
+4
+1
+5
+6
+1
+7
+7
+3
+0
+5
+2
+1
+9
+4
+3
+8
+6
+3
+7
+8
+2
+6
+5
+4
+8
+9
+8
+8
+1
+8
+4
+8
+7
+9
+8
+8
+8
+8
+8
+8
+8
+3
+8
+5
+8
+8
+8
+0
+3
+9
+9
+4
+2
+5
+8
+8
+5
+9
+9
+3
+6
+2
+7
+8
+3
+4
+5
+0
+8
+8
+2
+6
+3
+5
+6
+2
+7
+0
+1
+1
+0
+3
+9
+5
+7
+0
+3
+0
+9
+3
+1
+1
+0
+2
+5
+9
+5
+2
+4
+7
+7
+4
+3
+5
+1
+0
+7
+0
+5
+6
+2
+4
+3
+5
+0
+6
+5
+7
+7
+6
+2
+4
+6
+6
+4
+1
+0
+6
+9
+0
+6
+7
+1
+5
+7
+9
+3
+3
+2
+1
+4
+4
+3
+2
+9
+7
+1
+5
+2
+9
+0
+4
+0
+1
+3
+3
+1
+9
+5
+7
+7
+2
+7
+3
+0
+9
+2
+5
+9
+5
+0
+3
+0
+6
+6
+0
+2
+7
+3
+3
+2
+3
+9
+6
+6
+0
+6
+7
+4
+3
+1
+6
+6
+2
+7
+4
+6
+6
+6
+2
+9
+6
+2
+2
+4
+4
+1
+8
+8
+8
+8
+8
+8
+8
+8
+6
+8
+9
+4
+0
+2
+8
+8
+1
+7
+0
+4
+6
+9
+1
+6
+5
+1
+2
+3
+3
+9
+0
+4
+6
+6
+7
+6
+2
+5
+3
+1
+8
+4
+9
+8
+5
+3
+1
+7
+7
+8
+1
+8
+8
+1
+3
+8
+0
+5
+2
+8
+1
+8
+3
+2
+2
+0
+9
+5
+2
+3
+3
+8
+3
+2
+1
+0
+6
+0
+7
+7
+8
+1
+9
+9
+8
+6
+4
+8
+4
+6
+6
+9
+7
+3
+7
+4
+9
+6
+5
+9
+0
+5
+6
+3
+7
+4
+4
+7
+4
+3
+0
+1
+3
+4
+6
+9
+1
+3
+5
+0
+9
+7
+9
+9
+5
+4
+4
+2
+1
+4
+0
+5
+6
+6
+9
+2
+2
+7
+5
+1
+1
+4
+0
+9
+1
+2
+7
+6
+6
+3
+1
+5
+3
+1
+2
+1
+7
+7
+2
+9
+5
+0
+5
+2
+9
+5
+0
+1
+0
+7
+7
+7
+9
+0
+1
+3
+0
+2
+1
+0
+4
+1
+5
+3
+3
+6
+4
+5
+4
+6
+2
+3
+2
+4
+3
+5
+4
+0
+7
+9
+2
+3
+5
+4
+9
+4
+4
+0
+6
+2
+3
+6
+9
+4
+6
+5
+7
+0
+3
+7
+9
+5
+9
+4
+6
+3
+6
+2
+7
+9
+1
+7
+2
+1
+4
+1
+5
+9
+5
+1
+4
+0
+3
+0
+7
+9
+5
+7
+3
+5
+2
+0
+3
+0
+4
+1
+1
+3
+6
+6
+7
+1
+0
+2
+9
+3
+5
+2
+3
+5
+4
+5
+9
+3
+4
+9
+4
+2
+1
+5
+9
+1
+3
+0
+0
+5
+4
+3
+5
+9
+2
+8
+7
+4
+8
+1
+4
+9
+0
+5
+0
+8
+6
+4
+8
+8
+1
+8
+8
+8
+8
+8
+8
+8
+7
+8
+1
+8
+8
+8
+6
+6
+8
+1
+6
+8
+3
+2
+2
+0
+5
+3
+2
+5
+9
+5
+8
+4
+4
+3
+8
+2
+0
+7
+1
+9
+8
+3
+8
+0
+5
+8
+5
+0
+7
+7
+2
+4
+4
+2
+2
+1
+0
+0
+2
+0
+9
+7
+7
+7
+7
+0
+1
+0
+9
+4
+6
+5
+6
+6
+4
+3
+9
+0
+1
+3
+2
+3
+9
+1
+3
+4
+7
+4
+4
+1
+9
+6
+3
+9
+2
+0
+4
+3
+9
+2
+1
+9
+6
+1
+7
+6
+9
+4
+4
+5
+0
+5
+2
+4
+6
+9
+3
+6
+5
+6
+0
+2
+0
+9
+1
+4
+2
+6
+1
+0
+9
+0
+3
+1
+5
+2
+7
+7
+5
+3
+3
+9
+3
+7
+0
+1
+0
+9
+5
+7
+3
+0
+1
+2
+2
+1
+0
+1
+2
+1
+4
+5
+7
+9
+0
+7
+3
+5
+1
+4
+6
+4
+4
+5
+7
+8
+2
+8
+1
+8
+8
+8
+5
+8
+6
+6
+2
+0
+8
+1
+8
+8
+8
+8
+8
+8
+8
+3
+8
+8
+9
+8
+8
+8
+8
+3
+1
+9
+8
+8
+7
+8
+5
+3
+6
+5
+2
+1
+4
+0
+6
+3
+3
+6
+8
+8
+2
+7
+1
+8
+3
+1
+5
+8
+8
+5
+8
+8
+7
+7
+4
+0
+0
+0
+9
+5
+5
+9
+3
+2
+2
+7
+9
+2
+5
+9
+1
+4
+2
+1
+7
+0
+4
+0
+8
+8
+1
+2
+9
+4
+4
+3
+7
+1
+1
+5
+2
+4
+0
+5
+4
+2
+4
+7
+6
+9
+7
+1
+3
+5
+6
+6
+9
+3
+1
+3
+5
+6
+0
+7
+9
+5
+1
+6
+2
+0
+1
+0
+2
+9
+5
+7
+5
+2
+3
+5
+7
+7
+2
+3
+0
+4
+3
+5
+4
+9
+7
+2
+3
+7
+7
+5
+0
+9
+1
+2
+9
+7
+5
+0
+6
+6
+6
+5
+9
+1
+3
+7
+2
+0
+7
+7
+0
+2
+0
+9
+1
+2
+2
+1
+9
+1
+4
+5
+4
+5
+6
+2
+4
+3
+4
+9
+0
+0
+5
+0
+2
+9
+3
+4
+5
+7
+5
+0
+7
+2
+3
+1
+4
+1
+2
+6
+9
+5
+1
+7
+6
+6
+9
+3
+9
+1
+1
+6
+3
+4
+9
+7
+6
+6
+0
+3
+3
+2
+4
+1
+0
+0
+2
+6
+3
+4
+2
+7
+5
+9
+3
+5
+3
+5
+8
+8
+8
+8
+1
+8
+8
+8
+3
+8
+8
+4
+8
+8
+0
+1
+5
+0
+5
+2
+2
+3
+0
+5
+7
+2
+7
+7
+6
+2
+3
+6
+1
+8
+0
+8
+0
+3
+8
+8
+4
+7
+8
+1
+9
+3
+7
+5
+8
+8
+8
+8
+8
+8
+1
+8
+0
+1
+8
+2
+8
+3
+8
+7
+3
+0
+5
+8
+9
+2
+8
+1
+3
+6
+7
+7
+9
+0
+6
+6
+5
+4
+2
+0
+9
+1
+8
+6
+3
+8
+6
+5
+9
+3
+8
+0
+6
+6
+0
+4
+5
+7
+4
+3
+4
+5
+1
+5
+9
+9
+2
+3
+3
+5
+6
+5
+9
+7
+0
+3
+1
+0
+7
+8
+2
+9
+8
+3
+7
+2
+3
+7
+4
+9
+7
+5
+0
+3
+9
+4
+6
+6
+2
+1
+5
+7
+3
+2
+1
+9
+7
+2
+6
+6
+6
+5
+0
+9
+6
+1
+8
+8
+8
+8
+8
+8
+8
+8
+8
+5
+8
+8
+8
+8
+8
+8
+9
+7
+4
+5
+4
+3
+1
+6
+3
+1
+0
+4
+0
+8
+2
+1
+8
+9
+1
+4
+8
+4
+4
+2
+4
+9
+8
+8
+7
+6
+6
+4
+8
+9
+0
+8
+0
+5
+8
+3
+8
+9
+8
+8
+5
+7
+2
+3
+6
+6
+3
+2
+6
+6
+5
+1
+2
+3
+3
+5
+5
+4
+1
+3
+8
+2
+4
+5
+5
+1
+9
+1
+7
+7
+3
+0
+1
+0
+2
+7
+0
+5
+3
+4
+3
+7
+4
+9
+2
+3
+1
+7
+3
+6
+9
+9
+4
+2
+5
+0
+0
+5
+9
+4
+7
+4
+4
+6
+4
+1
+9
+2
+4
+3
+9
+0
+9
+9
+1
+4
+7
+4
+9
+2
+4
+9
+7
+0
+2
+4
+3
+5
+1
+9
+1
+3
+6
+3
+5
+4
+6
+5
+6
+7
+2
+5
+0
+4
+0
+6
+4
+5
+7
+0
+6
+2
+2
+5
+6
+4
+5
+6
+9
+6
+3
+2
+0
+6
+0
+7
+9
+1
+3
+0
+2
+2
+4
+0
+2
+9
+7
+7
+5
+4
+1
+5
+9
+0
+2
+0
+1
+0
+7
+4
+4
+9
+4
+2
+7
+1
+1
+5
+5
+9
+1
+4
+4
+6
+9
+7
+0
+0
+0
+3
+7
+2
+6
+6
+1
+6
+2
+1
+0
+4
+4
+6
+5
+9
+7
+2
+6
+0
+9
+0
+1
+9
+5
+3
+2
+2
+4
+9
+0
+3
+5
+7
+3
+9
+2
+6
+7
+2
+4
+8
+6
+2
+2
+9
+4
+3
+2
+6
+3
+0
+0
+2
+5
+7
+3
+5
+3
+9
+6
+4
+4
+6
+9
+8
+0
+7
+3
+8
+8
+8
+9
+8
+5
+2
+8
+8
+8
+8
+2
+7
+8
+8
+8
+8
+8
+5
+0
+8
+8
+4
+7
+7
+2
+0
+9
+0
+2
+1
+1
+5
+4
+2
+6
+6
+1
+3
+3
+7
+0
+5
+9
+8
+7
+1
+3
+2
+6
+6
+1
+5
+1
+5
+3
+5
+3
+1
+6
+9
+6
+0
+5
+0
+1
+2
+7
+7
+7
+7
+5
+1
+6
+7
+9
+9
+4
+3
+4
+2
+1
+0
+5
+0
+2
+3
+9
+7
+7
+4
+6
+6
+4
+0
+9
+1
+2
+6
+4
+7
+6
+5
+9
+5
+6
+2
+1
+3
+7
+3
+9
+4
+4
+0
+4
+0
+8
+3
+0
+9
+5
+7
+4
+1
+2
+5
+9
+3
+2
+4
+0
+4
+5
+2
+7
+2
+3
+2
+0
+5
+4
+3
+2
+2
+3
+5
+6
+2
+6
+6
+9
+9
+3
+1
+5
+7
+2
+1
+6
+9
+6
+6
+3
+1
+9
+7
+6
+5
+7
+2
+2
+6
+0
+4
+0
+9
+4
+0
+1
+2
+1
+7
+6
+0
+6
+3
+4
+7
+9
+5
+7
+9
+1
+4
+0
+4
+4
+2
+5
+1
+5
+0
+2
+0
+9
+5
+1
+7
+1
+5
+5
+2
+7
+0
+5
+2
+6
+4
+3
+4
+7
+0
+4
+0
+2
+8
+3
+8
+2
+4
+8
+3
+8
+8
+9
+8
+8
+2
+8
+5
+8
+8
+9
+6
+8
+1
+7
+0
+1
+3
+9
+9
+2
+9
+8
+5
+5
+3
+6
+9
+6
+6
+7
+7
+4
+0
+6
+0
+8
+6
+2
+3
+6
+1
+9
+2
+0
+0
+6
+2
+0
+4
+0
+4
+4
+1
+1
+0
+2
+3
+7
+9
+1
+7
+4
+1
+1
+2
+2
+1
+5
+4
+2
+5
+4
+3
+1
+7
+3
+7
+0
+0
+9
+5
+4
+3
+2
+2
+7
+7
+5
+4
+6
+6
+4
+5
+0
+1
+9
+2
+2
+3
+3
+9
+2
+7
+0
+6
+0
+3
+7
+7
+5
+9
+7
+4
+3
+3
+1
+5
+4
+9
+0
+5
+7
+7
+2
+7
+0
+9
+2
+4
+5
+0
+3
+2
+6
+9
+4
+2
+2
+7
+3
+1
+4
+9
+1
+0
+6
+0
+9
+4
+3
+7
+5
+6
+1
+5
+7
+0
+1
+9
+6
+6
+4
+3
+6
+5
+5
+0
+5
+4
+2
+4
+9
+7
+5
+2
+6
+4
+7
+2
+0
+1
+7
+9
+7
+7
+5
+0
+1
+9
+3
+9
+2
+2
+2
+1
+9
+3
+7
+7
+0
+7
+1
+6
+6
+3
+8
+8
+8
+8
+8
+7
+8
+8
+8
+3
+0
+6
+8
+5
+8
+8
+3
+1
+3
+1
+4
+7
+6
+9
+1
+0
+3
+4
+2
+8
+4
+9
+0
+4
+3
+8
+4
+8
+8
+8
+6
+6
+3
+5
+8
+8
+6
+8
+8
+8
+8
+8
+8
+8
+6
+8
+8
+8
+8
+8
+8
+8
+7
+5
+6
+5
+1
+6
+7
+7
+6
+0
+0
+2
+7
+9
+4
+5
+8
+5
+1
+0
+5
+8
+8
+8
+2
+5
+8
+3
+7
+9
+8
+0
+5
+8
+9
+1
+5
+9
+3
+2
+7
+1
+9
+2
+0
+5
+6
+6
+1
+6
+8
+3
+2
+0
+3
+7
+2
+7
+4
+5
+6
+2
+1
+8
+1
+6
+2
+6
+0
+1
+0
+2
+6
+4
+9
+4
+1
+3
+4
+5
+3
+1
+9
+1
+2
+3
+3
+8
+7
+5
+1
+3
+1
+2
+2
+4
+5
+1
+5
+4
+0
+3
+0
+6
+5
+6
+6
+1
+6
+3
+9
+4
+0
+9
+6
+6
+6
+6
+1
+7
+0
+9
+0
+5
+2
+0
+3
+0
+9
+5
+7
+7
+1
+2
+9
+1
+3
+9
+5
+2
+5
+0
+9
+2
+3
+9
+4
+7
+5
+3
+9
+5
+7
+7
+5
+4
+4
+1
+9
+6
+3
+6
+5
+4
+7
+0
+2
+0
+3
+1
+3
+2
+6
+4
+7
+4
+1
+7
+6
+6
+7
+7
+5
+1
+6
+0
+4
+0
+2
+2
+1
+9
+1
+5
+3
+5
+6
+1
+2
+9
+0
+3
+0
+2
+9
+0
+4
+8
+7
+7
+3
+1
+7
+1
+9
+9
+2
+5
+1
+7
+0
+2
+6
+6
+5
+2
+6
+6
+6
+9
+7
+7
+1
+5
+2
+1
+9
+9
+8
+3
+5
+8
+5
+4
+4
+9
+1
+3
+3
+8
+0
+1
+7
+5
+6
+6
+2
+1
+9
+7
+1
+4
+2
+4
+0
+1
+0
+6
+9
+1
+1
+2
+6
+3
+9
+2
+9
+9
+7
+6
+7
+6
+9
+4
+0
+1
+0
+5
+3
+5
+7
+9
+7
+6
+2
+0
+6
+1
+2
+9
+3
+4
+7
+2
+5
+0
+5
+7
+1
+7
+8
+1
+2
+3
+9
+9
+2
+9
+1
+7
+1
+3
+2
+3
+3
+2
+2
+2
+5
+0
+0
+5
+1
+5
+7
+2
+9
+7
+4
+1
+7
+7
+5
+6
+2
+4
+1
+3
+4
+0
+4
+5
+6
+2
+4
+7
+5
+7
+9
+1
+1
+4
+0
+3
+4
+1
+2
+6
+5
+3
+5
+0
+4
+7
+9
+2
+7
+3
+6
+6
+3
+0
+9
+0
+4
+1
+0
+3
+7
+4
+3
+9
+4
+2
+4
+5
+0
+6
+0
+7
+7
+4
+1
+5
+6
+7
+0
+2
+6
+4
+0
+3
+5
+1
+7
+9
+0
+7
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+2
+8
+1
+8
+5
+4
+1
+4
+4
+1
+0
+1
+7
+7
+9
+4
+1
+8
+4
+7
+8
+0
+9
+9
+5
+4
+3
+2
+7
+5
+6
+9
+0
+0
+3
+4
+6
+5
+8
+8
+8
+0
+8
+8
+1
+7
+9
+8
+8
+5
+3
+0
+4
+0
+5
+3
+8
+5
+9
+4
+6
+6
+4
+0
+4
+6
+3
+7
+2
+9
+7
+3
+1
+0
+5
+6
+8
+2
+8
+3
+7
+4
+8
+0
+6
+6
+6
+6
+5
+3
+9
+2
+7
+5
+7
+2
+1
+3
+0
+5
+2
+5
+1
+4
+8
+4
+9
+8
+4
+2
+5
+1
+1
+5
+7
+4
+3
+1
+5
+2
+7
+7
+0
+1
+3
+4
+7
+2
+4
+6
+1
+6
+2
+4
+1
+0
+6
+1
+9
+9
+6
+2
+0
+7
+1
+4
+4
+9
+3
+6
+2
+1
+9
+0
+6
+7
+4
+5
+1
+2
+9
+1
+0
+5
+2
+1
+6
+4
+7
+7
+7
+9
+5
+0
+5
+0
+9
+5
+2
+3
+3
+5
+5
+9
+6
+0
+6
+6
+3
+1
+2
+7
+5
+3
+5
+0
+3
+6
+9
+2
+1
+3
+5
+4
+7
+4
+4
+7
+5
+2
+3
+1
+3
+4
+3
+5
+7
+1
+2
+7
+9
+5
+3
+4
+1
+4
+4
+2
+1
+0
+9
+9
+2
+7
+4
+3
+5
+6
+0
+9
+0
+2
+6
+3
+0
+3
+5
+9
+0
+6
+7
+1
+9
+3
+0
+6
+0
+8
+1
+2
+4
+6
+1
+6
+2
+1
+5
+7
+9
+3
+3
+5
+1
+2
+0
+3
+8
+4
+4
+5
+4
+8
+2
+8
+8
+9
+1
+8
+3
+1
+8
+2
+8
+8
+8
+8
+3
+8
+8
+8
+8
+9
+8
+8
+6
+8
+8
+6
+6
+2
+6
+4
+7
+4
+4
+9
+4
+3
+2
+7
+4
+5
+9
+9
+4
+9
+5
+2
+0
+7
+9
+4
+2
+7
+3
+7
+6
+6
+0
+9
+1
+4
+1
+7
+3
+7
+2
+0
+6
+0
+2
+1
+9
+4
+6
+9
+1
+0
+3
+2
+5
+7
+6
+6
+2
+3
+7
+0
+3
+0
+9
+9
+6
+5
+2
+6
+9
+0
+7
+1
+1
+4
+2
+3
+0
+5
+3
+2
+4
+7
+5
+3
+7
+1
+7
+4
+5
+4
+4
+3
+4
+2
+5
+9
+7
+4
+0
+1
+0
+3
+3
+0
+0
+0
+2
+5
+6
+4
+0
+6
+7
+7
+7
+2
+5
+9
+3
+9
+1
+5
+6
+6
+9
+9
+3
+4
+9
+5
+0
+9
+0
+2
+3
+7
+5
+1
+5
+9
+3
+6
+3
+4
+4
+0
+2
+3
+7
+7
+0
+2
+9
+6
+6
+6
+2
+0
+3
+1
+8
+9
+8
+8
+8
+8
+8
+8
+8
+9
+8
+1
+8
+0
+8
+8
+9
+4
+6
+6
+4
+3
+7
+2
+9
+5
+9
+4
+2
+8
+4
+5
+3
+5
+7
+0
+0
+4
+4
+1
+5
+9
+5
+8
+7
+7
+2
+3
+3
+9
+1
+7
+8
+5
+8
+2
+3
+6
+8
+8
+1
+7
+6
+6
+5
+2
+4
+1
+1
+5
+9
+3
+0
+7
+3
+5
+5
+1
+2
+3
+6
+4
+4
+6
+5
+8
+9
+2
+1
+9
+0
+8
+0
+2
+9
+5
+2
+5
+7
+7
+9
+9
+0
+3
+0
+2
+5
+6
+7
+7
+6
+3
+7
+6
+5
+4
+1
+9
+2
+6
+4
+1
+0
+2
+5
+9
+5
+4
+2
+6
+9
+6
+9
+0
+5
+4
+7
+4
+9
+1
+4
+9
+7
+7
+1
+4
+7
+5
+5
+9
+5
+3
+3
+0
+3
+2
+7
+6
+4
+5
+3
+3
+9
+4
+3
+2
+0
+0
+5
+0
+9
+9
+3
+6
+6
+6
+0
+3
+1
+4
+6
+1
+4
+1
+7
+3
+9
+2
+5
+0
+7
+3
+6
+6
+9
+3
+3
+2
+5
+4
+6
+3
+4
+3
+0
+1
+2
+1
+6
+1
+2
+5
+3
+7
+5
+2
+1
+3
+7
+2
+2
+4
+4
+5
+0
+4
+4
+0
+2
+6
+6
+5
+7
+7
+0
+4
+0
+2
+4
+0
+5
+3
+6
+6
+3
+5
+9
+5
+4
+7
+2
+2
+3
+5
+9
+7
+2
+9
+0
+3
+2
+1
+5
+9
+0
+5
+7
+1
+1
+8
+3
+9
+4
+0
+2
+3
+3
+7
+0
+9
+6
+6
+5
+3
+3
+0
+6
+9
+8
+4
+4
+8
+2
+3
+8
+5
+5
+2
+6
+4
+9
+0
+1
+8
+8
+8
+8
+8
+8
+1
+8
+8
+8
+8
+8
+8
+1
+8
+8
+2
+3
+7
+0
+1
+9
+3
+7
+4
+3
+5
+1
+5
+4
+9
+0
+1
+8
+1
+8
+5
+9
+3
+2
+0
+1
+0
+5
+2
+6
+6
+8
+2
+5
+6
+2
+2
+7
+5
+1
+4
+2
+1
+3
+2
+5
+4
+9
+9
+2
+4
+4
+6
+1
+7
+0
+9
+3
+5
+2
+4
+0
+4
+4
+9
+7
+3
+2
+5
+9
+1
+4
+2
+4
+3
+5
+0
+9
+0
+1
+4
+1
+7
+3
+0
+0
+2
+7
+7
+6
+6
+6
+6
+9
+5
+2
+0
+2
+1
+7
+7
+3
+5
+9
+6
+1
+3
+6
+6
+2
+9
+0
+7
+7
+4
+6
+7
+4
+2
+5
+1
+0
+5
+3
+4
+3
+4
+4
+9
+6
+0
+6
+1
+5
+9
+0
+2
+4
+7
+5
+3
+2
+1
+7
+7
+0
+1
+7
+1
+3
+9
+2
+4
+1
+6
+0
+3
+0
+9
+6
+6
+7
+0
+7
+7
+3
+5
+1
+4
+9
+1
+4
+5
+4
+8
+5
+2
+9
+7
+7
+9
+5
+0
+5
+3
+9
+2
+0
+9
+0
+6
+4
+6
+8
+9
+8
+8
+8
+0
+2
+8
+6
+9
+5
+6
+7
+5
+3
+0
+8
+8
+8
+8
+8
+8
+8
+8
+4
+9
+8
+8
+8
+7
+5
+4
+5
+1
+6
+6
+8
+3
+9
+4
+7
+7
+4
+2
+4
+3
+9
+8
+2
+0
+8
+8
+8
+3
+3
+1
+8
+2
+8
+0
+0
+6
+7
+7
+0
+9
+2
+1
+1
+7
+9
+2
+3
+9
+1
+7
+0
+5
+6
+3
+3
+1
+0
+4
+6
+6
+4
+5
+1
+2
+6
+7
+4
+1
+9
+1
+3
+8
+5
+0
+9
+9
+1
+4
+3
+1
+0
+5
+0
+6
+7
+2
+4
+8
+0
+2
+1
+6
+1
+4
+2
+4
+4
+6
+4
+9
+0
+5
+3
+5
+9
+5
+4
+1
+6
+3
+3
+0
+2
+7
+1
+4
+4
+3
+1
+0
+9
+2
+2
+9
+4
+5
+7
+7
+9
+1
+1
+2
+5
+3
+5
+0
+3
+9
+7
+7
+2
+7
+1
+4
+3
+9
+5
+1
+5
+2
+4
+1
+9
+0
+5
+0
+5
+1
+6
+6
+3
+5
+6
+2
+6
+0
+7
+4
+4
+1
+4
+6
+7
+0
+9
+3
+1
+4
+3
+1
+0
+2
+6
+3
+6
+6
+7
+4
+0
+7
+1
+3
+1
+9
+4
+2
+5
+4
+5
+3
+0
+4
+0
+7
+5
+7
+4
+1
+6
+6
+5
+6
+0
+9
+6
+6
+3
+2
+1
+7
+9
+2
+0
+4
+3
+7
+2
+2
+9
+1
+8
+8
+8
+8
+8
+8
+8
+8
+5
+8
+8
+8
+8
+8
+2
+8
+0
+4
+4
+2
+7
+5
+9
+2
+2
+3
+0
+1
+6
+6
+5
+9
+7
+7
+8
+4
+9
+4
+4
+8
+1
+6
+2
+5
+9
+7
+3
+0
+8
+8
+8
+8
+9
+8
+7
+6
+2
+0
+8
+3
+9
+8
+1
+5
+6
+2
+7
+1
+9
+3
+3
+6
+0
+7
+1
+4
+7
+7
+4
+7
+0
+0
+5
+7
+9
+8
+3
+5
+1
+8
+1
+3
+9
+7
+3
+4
+6
+6
+9
+3
+0
+2
+1
+5
+4
+1
+7
+7
+3
+9
+5
+4
+5
+3
+2
+2
+1
+5
+1
+0
+7
+0
+9
+2
+2
+9
+5
+1
+5
+2
+1
+9
+7
+2
+0
+7
+0
+5
+9
+9
+6
+3
+2
+2
+1
+4
+2
+9
+4
+7
+3
+2
+6
+6
+6
+9
+2
+4
+4
+5
+9
+7
+7
+4
+6
+4
+6
+5
+3
+6
+6
+9
+7
+3
+1
+4
+5
+7
+0
+9
+0
+3
+7
+7
+9
+0
+4
+9
+2
+3
+1
+7
+8
+8
+8
+8
+8
+8
+8
+8
+8
+9
+1
+8
+8
+1
+2
+8
+7
+1
+4
+7
+4
+3
+3
+2
+6
+6
+5
+0
+6
+8
+6
+6
+3
+8
+4
+8
+9
+8
+7
+0
+8
+0
+8
+8
+9
+8
+5
+3
+8
+8
+8
+8
+7
+8
+8
+8
+3
+8
+8
+8
+8
+0
+6
+2
+7
+8
+1
+7
+5
+1
+5
+4
+6
+2
+3
+6
+4
+7
+6
+3
+6
+5
+8
+8
+9
+8
+2
+3
+8
+8
+5
+1
+9
+5
+0
+3
+2
+3
+0
+6
+9
+9
+4
+5
+1
+3
+3
+7
+7
+9
+1
+7
+5
+0
+3
+4
+9
+9
+4
+1
+0
+4
+3
+5
+7
+6
+1
+7
+4
+0
+9
+1
+5
+2
+5
+4
+7
+4
+4
+0
+3
+1
+6
+6
+8
+5
+2
+0
+6
+9
+8
+6
+1
+3
+5
+2
+3
+5
+7
+7
+9
+9
+7
+2
+2
+5
+1
+5
+9
+9
+0
+0
+3
+7
+4
+6
+9
+3
+7
+7
+1
+6
+5
+3
+9
+3
+2
+5
+7
+7
+0
+1
+2
+6
+1
+9
+2
+1
+6
+6
+7
+7
+4
+3
+1
+2
+9
+5
+4
+9
+6
+6
+3
+1
+2
+0
+5
+9
+2
+1
+3
+5
+7
+7
+2
+4
+5
+3
+2
+7
+3
+5
+0
+2
+7
+4
+3
+0
+3
+4
+0
+9
+2
+3
+3
+4
+9
+1
+6
+7
+0
+6
+0
+6
+9
+2
+2
+9
+0
+1
+2
+7
+9
+9
+6
+2
+1
+6
+4
+8
+9
+5
+6
+1
+0
+6
+7
+7
+2
+0
+5
+0
+7
+2
+2
+3
+9
+9
+8
+8
+8
+8
+8
+8
+8
+2
+8
+8
+8
+8
+5
+3
+8
+8
+6
+4
+4
+6
+1
+9
+3
+0
+7
+5
+9
+5
+9
+8
+7
+1
+3
+8
+1
+5
+5
+4
+4
+8
+4
+8
+7
+9
+1
+2
+8
+5
+1
+0
+8
+8
+8
+3
+8
+8
+5
+4
+9
+0
+6
+0
+2
+8
+0
+1
+5
+2
+2
+5
+7
+3
+6
+6
+0
+9
+0
+4
+6
+3
+3
+2
+0
+9
+7
+6
+6
+6
+3
+8
+2
+9
+5
+3
+0
+3
+9
+7
+6
+5
+5
+6
+6
+0
+2
+0
+1
+9
+4
+1
+7
+5
+9
+1
+9
+9
+1
+8
+7
+4
+0
+4
+3
+9
+4
+1
+4
+3
+4
+5
+2
+6
+6
+0
+9
+3
+7
+7
+0
+7
+2
+5
+9
+3
+3
+4
+5
+6
+0
+2
+1
+5
+3
+9
+2
+4
+1
+4
+9
+7
+5
+9
+3
+4
+7
+4
+9
+2
+4
+0
+3
+7
+2
+6
+9
+6
+1
+0
+1
+9
+5
+2
+9
+3
+7
+5
+6
+1
+4
+0
+9
+3
+8
+5
+8
+8
+8
+8
+8
+1
+8
+8
+8
+8
+3
+8
+1
+8
+6
+4
+5
+0
+4
+0
+9
+9
+5
+3
+3
+2
+2
+8
+5
+0
+5
+7
+0
+1
+9
+4
+4
+8
+4
+8
+1
+3
+9
+1
+0
+4
+8
+1
+8
+8
+9
+8
+7
+7
+1
+6
+8
+8
+9
+8
+2
+8
+4
+5
+0
+9
+0
+7
+2
+4
+5
+1
+4
+9
+4
+5
+0
+8
+2
+3
+5
+8
+1
+5
+0
+8
+0
+2
+7
+9
+3
+4
+6
+1
+9
+7
+1
+3
+3
+1
+7
+2
+9
+6
+6
+2
+1
+0
+6
+4
+0
+6
+9
+4
+7
+4
+4
+7
+8
+2
+9
+3
+3
+8
+2
+5
+7
+5
+2
+0
+0
+0
+3
+4
+5
+4
+4
+2
+2
+3
+1
+0
+2
+7
+5
+3
+4
+5
+3
+0
+9
+0
+9
+4
+6
+6
+3
+7
+5
+9
+2
+1
+1
+3
+0
+2
+3
+6
+1
+5
+7
+1
+6
+7
+9
+1
+7
+1
+5
+3
+6
+6
+1
+9
+0
+6
+7
+7
+2
+5
+7
+7
+7
+7
+9
+3
+1
+9
+0
+1
+2
+1
+9
+3
+6
+6
+4
+7
+5
+2
+6
+6
+7
+4
+6
+2
+6
+6
+5
+3
+3
+1
+3
+6
+7
+0
+4
+9
+5
+6
+3
+7
+6
+4
+7
+7
+4
+2
+1
+6
+0
+5
+0
+4
+4
+0
+3
+2
+4
+1
+9
+2
+0
+5
+4
+5
+2
+5
+9
+9
+2
+0
+5
+0
+9
+2
+4
+8
+1
+2
+3
+0
+5
+1
+2
+5
+3
+3
+6
+2
+0
+6
+5
+0
+7
+7
+8
+3
+4
+1
+6
+6
+5
+6
+7
+3
+1
+7
+0
+1
+8
+8
+8
+1
+8
+8
+8
+0
+8
+8
+1
+7
+8
+8
+8
+8
+8
+4
+0
+2
+3
+4
+8
+6
+4
+5
+4
+1
+6
+6
+0
+8
+2
+7
+5
+9
+7
+0
+1
+8
+8
+2
+2
+9
+3
+8
+7
+8
+8
+1
+6
+2
+0
+6
+0
+1
+9
+0
+7
+5
+2
+7
+3
+4
+0
+2
+1
+3
+3
+5
+2
+1
+9
+8
+0
+3
+5
+1
+6
+6
+7
+6
+0
+0
+2
+4
+3
+7
+9
+5
+6
+6
+7
+3
+3
+0
+1
+9
+4
+6
+5
+2
+3
+5
+6
+4
+2
+4
+4
+7
+4
+2
+9
+0
+6
+4
+6
+0
+4
+0
+3
+7
+4
+5
+1
+4
+9
+1
+3
+9
+2
+1
+6
+2
+7
+4
+9
+0
+1
+0
+5
+3
+3
+2
+9
+9
+6
+0
+6
+6
+5
+9
+1
+6
+4
+1
+0
+3
+7
+0
+2
+5
+4
+5
+7
+0
+3
+9
+1
+2
+5
+3
+5
+1
+2
+7
+0
+0
+8
+8
+8
+8
+8
+5
+3
+8
+8
+8
+8
+8
+8
+8
+3
+6
+1
+4
+4
+3
+4
+6
+5
+2
+2
+7
+9
+4
+2
+8
+7
+7
+8
+6
+9
+4
+5
+3
+0
+1
+0
+5
+7
+7
+8
+3
+1
+4
+0
+5
+8
+8
+8
+8
+3
+2
+5
+8
+0
+7
+1
+3
+3
+8
+3
+2
+5
+1
+7
+0
+7
+7
+3
+8
+1
+9
+8
+6
+5
+0
+5
+1
+9
+9
+7
+7
+8
+0
+3
+6
+1
+6
+5
+2
+6
+6
+2
+9
+6
+5
+5
+0
+1
+7
+7
+2
+7
+7
+1
+3
+9
+0
+8
+5
+2
+4
+1
+4
+4
+0
+7
+7
+7
+2
+6
+3
+6
+1
+2
+2
+1
+7
+7
+6
+0
+3
+0
+4
+4
+6
+4
+0
+5
+3
+3
+0
+2
+6
+4
+7
+5
+9
+3
+5
+7
+0
+2
+4
+4
+9
+0
+7
+3
+5
+9
+2
+7
+1
+1
+5
+0
+5
+0
+1
+1
+5
+3
+5
+2
+5
+7
+3
+7
+7
+5
+0
+5
+2
+9
+6
+0
+9
+4
+3
+5
+1
+9
+2
+0
+0
+6
+6
+1
+4
+9
+9
+6
+6
+7
+1
+2
+1
+9
+6
+0
+6
+1
+3
+3
+4
+2
+4
+4
+9
+2
+4
+4
+5
+2
+2
+1
+7
+9
+3
+5
+4
+6
+2
+4
+6
+3
+0
+3
+9
+6
+6
+2
+6
+4
+1
+3
+9
+0
+0
+6
+1
+5
+7
+1
+7
+2
+5
+6
+6
+9
+2
+0
+0
+5
+8
+5
+0
+9
+3
+3
+0
+0
+0
+7
+2
+9
+5
+3
+1
+3
+4
+0
+0
+8
+4
+4
+3
+0
+8
+8
+1
+8
+9
+5
+3
+6
+7
+1
+8
+8
+8
+8
+8
+8
+8
+8
+5
+8
+9
+6
+3
+8
+8
+8
+2
+2
+9
+5
+1
+6
+5
+0
+6
+7
+2
+1
+0
+5
+3
+9
+1
+0
+1
+6
+3
+8
+8
+3
+8
+1
+5
+0
+2
+0
+4
+3
+7
+1
+0
+7
+7
+6
+9
+3
+9
+2
+1
+5
+0
+7
+9
+3
+5
+0
+2
+6
+3
+1
+0
+1
+5
+5
+1
+0
+3
+9
+7
+5
+1
+5
+6
+1
+4
+2
+0
+3
+1
+2
+7
+4
+5
+5
+3
+7
+0
+1
+2
+7
+3
+9
+9
+3
+4
+0
+4
+4
+1
+4
+3
+3
+6
+3
+4
+9
+2
+2
+9
+0
+1
+7
+6
+5
+6
+6
+5
+1
+5
+0
+0
+9
+4
+6
+3
+6
+5
+3
+7
+9
+7
+0
+3
+5
+2
+5
+6
+6
+9
+2
+7
+6
+3
+3
+2
+7
+9
+0
+2
+5
+3
+4
+1
+0
+1
+0
+7
+5
+4
+1
+5
+4
+7
+2
+6
+0
+3
+4
+3
+2
+0
+6
+0
+1
+6
+7
+1
+9
+7
+4
+9
+5
+3
+5
+6
+3
+6
+1
+9
+1
+0
+7
+3
+3
+5
+5
+9
+7
+1
+8
+8
+1
+8
+8
+1
+2
+8
+0
+5
+7
+2
+1
+8
+8
+8
+8
+8
+8
+8
+3
+4
+8
+8
+4
+6
+8
+7
+3
+5
+8
+8
+0
+1
+2
+9
+8
+6
+7
+7
+1
+4
+4
+9
+4
+1
+5
+0
+5
+6
+0
+6
+0
+2
+8
+1
+8
+2
+9
+9
+5
+4
+0
+8
+9
+6
+2
+9
+1
+3
+5
+0
+9
+0
+9
+2
+2
+1
+3
+1
+2
+7
+9
+9
+5
+2
+7
+8
+8
+4
+5
+9
+6
+5
+3
+5
+6
+6
+5
+6
+7
+1
+1
+9
+0
+1
+2
+1
+4
+3
+5
+9
+4
+0
+5
+2
+1
+7
+9
+4
+9
+1
+4
+5
+5
+6
+3
+1
+7
+7
+1
+7
+5
+1
+2
+9
+3
+5
+2
+4
+9
+4
+4
+6
+1
+5
+1
+0
+6
+0
+7
+6
+4
+2
+6
+1
+1
+2
+0
+9
+6
+6
+0
+7
+0
+6
+2
+3
+1
+4
+4
+2
+9
+7
+0
+3
+7
+1
+7
+7
+9
+3
+0
+1
+0
+2
+1
+5
+9
+2
+1
+9
+3
+4
+3
+4
+5
+9
+2
+3
+7
+5
+3
+0
+6
+1
+7
+7
+2
+5
+0
+1
+2
+4
+4
+3
+4
+2
+6
+6
+7
+9
+7
+4
+7
+2
+5
+7
+9
+5
+1
+3
+4
+1
+2
+0
+7
+0
+2
+4
+7
+7
+9
+9
+1
+0
+5
+3
+9
+6
+4
+5
+4
+7
+6
+1
+8
+8
+8
+0
+6
+8
+8
+8
+8
+9
+8
+8
+7
+8
+2
+5
+1
+5
+3
+6
+2
+1
+6
+2
+5
+0
+3
+1
+7
+7
+7
+7
+8
+2
+5
+4
+3
+8
+4
+5
+0
+7
+2
+8
+3
+8
+5
+8
+8
+9
+8
+8
+8
+8
+8
+1
+2
+9
+4
+5
+4
+8
+7
+6
+8
+4
+4
+3
+5
+7
+9
+7
+6
+6
+7
+7
+3
+4
+9
+5
+8
+6
+0
+2
+0
+6
+9
+6
+5
+9
+1
+7
+3
+5
+0
+4
+1
+2
+5
+0
+3
+9
+1
+5
+4
+1
+2
+1
+5
+9
+7
+0
+5
+3
+0
+8
+1
+9
+6
+6
+2
+5
+6
+2
+3
+9
+7
+1
+4
+6
+9
+6
+5
+2
+3
+0
+0
+0
+9
+7
+1
+9
+3
+5
+1
+0
+2
+3
+4
+9
+8
+2
+5
+7
+7
+2
+2
+4
+4
+5
+0
+1
+9
+4
+7
+2
+4
+7
+4
+4
+0
+3
+6
+3
+2
+6
+5
+1
+2
+3
+0
+6
+5
+1
+6
+4
+7
+6
+2
+3
+1
+6
+3
+7
+0
+5
+0
+6
+6
+6
+3
+0
+9
+9
+7
+4
+2
+5
+6
+4
+4
+9
+7
+3
+0
+2
+3
+2
+1
+4
+2
+1
+3
+1
+0
+9
+8
+8
+8
+3
+6
+6
+8
+2
+0
+8
+0
+3
+7
+7
+8
+8
+8
+8
+1
+4
+8
+8
+4
+9
+8
+8
+7
+8
+8
+1
+3
+9
+1
+8
+8
+1
+9
+4
+7
+2
+4
+5
+4
+3
+9
+8
+1
+9
+2
+8
+5
+3
+0
+8
+6
+6
+8
+1
+2
+4
+7
+6
+2
+5
+8
+5
+7
+6
+9
+3
+1
+6
+7
+0
+0
+5
+9
+3
+6
+6
+6
+4
+0
+0
+9
+1
+3
+9
+7
+7
+2
+3
+5
+3
+4
+7
+3
+6
+0
+2
+7
+4
+3
+3
+1
+5
+5
+1
+0
+9
+3
+4
+3
+1
+5
+3
+9
+9
+0
+5
+3
+2
+6
+4
+4
+6
+1
+4
+3
+6
+4
+7
+1
+3
+5
+1
+3
+7
+1
+4
+4
+3
+3
+0
+9
+4
+1
+5
+0
+3
+7
+1
+9
+7
+9
+6
+5
+1
+5
+3
+1
+9
+7
+1
+7
+7
+1
+6
+9
+9
+1
+2
+6
+6
+0
+4
+3
+0
+6
+7
+2
+6
+6
+3
+0
+1
+0
+4
+4
+5
+6
+4
+4
+6
+4
+0
+6
+6
+9
+2
+5
+9
+3
+5
+0
+0
+7
+3
+5
+9
+3
+5
+7
+7
+4
+0
+9
+9
+3
+7
+1
+2
+9
+0
+7
+7
+1
+2
+0
+4
+9
+2
+1
+5
+6
+1
+3
+1
+9
+0
+7
+3
+5
+0
+2
+2
+9
+5
+6
+0
+0
+1
+4
+2
+8
+8
+8
+8
+8
+8
+8
+8
+8
+1
+8
+8
+8
+6
+8
+8
+0
+2
+4
+4
+7
+5
+7
+9
+6
+6
+0
+6
+5
+6
+2
+1
+7
+8
+1
+4
+6
+1
+4
+8
+2
+8
+0
+5
+9
+7
+3
+0
+1
+7
+6
+5
+9
+8
+8
+8
+8
+4
+4
+1
+9
+8
+3
+5
+2
+1
+4
+2
+4
+9
+3
+0
+2
+0
+5
+4
+7
+9
+4
+7
+8
+2
+7
+8
+9
+3
+3
+1
+4
+8
+2
+0
+5
+7
+6
+6
+3
+0
+5
+2
+2
+9
+5
+3
+6
+7
+6
+6
+0
+1
+6
+3
+6
+6
+0
+5
+5
+0
+6
+4
+3
+4
+4
+7
+9
+9
+7
+0
+4
+5
+7
+9
+4
+3
+1
+4
+6
+1
+0
+1
+7
+7
+6
+7
+5
+4
+7
+0
+1
+0
+6
+6
+3
+1
+6
+4
+5
+4
+4
+0
+6
+9
+2
+6
+0
+1
+5
+3
+4
+5
+7
+5
+2
+2
+7
+4
+1
+9
+1
+5
+5
+2
+0
+3
+0
+9
+5
+1
+4
+0
+7
+3
+9
+1
+3
+2
+4
+7
+9
+5
+1
+3
+3
+7
+2
+0
+9
+6
+0
+4
+3
+0
+6
+2
+2
+1
+7
+7
+0
+4
+5
+1
+9
+0
+5
+6
+0
+0
+3
+7
+6
+2
+4
+5
+6
+5
+3
+1
+9
+9
+4
+3
+3
+5
+5
+7
+9
+0
+0
+0
+5
+0
+4
+1
+2
+5
+4
+6
+3
+7
+9
+6
+1
+4
+8
+4
+4
+0
+4
+0
+8
+5
+7
+5
+8
+7
+1
+0
+8
+3
+5
+2
+3
+4
+9
+4
+4
+1
+8
+3
+5
+4
+3
+5
+4
+5
+4
+3
+3
+2
+3
+9
+7
+7
+2
+3
+3
+4
+9
+9
+5
+0
+6
+0
+3
+1
+7
+9
+6
+7
+4
+1
+9
+3
+6
+6
+0
+4
+0
+5
+4
+2
+2
+9
+6
+5
+0
+5
+6
+6
+3
+2
+6
+1
+5
+7
+0
+4
+0
+4
+7
+0
+6
+5
+2
+1
+7
+7
+3
+2
+4
+1
+1
+3
+2
+1
+3
+4
+5
+2
+0
+3
+0
+2
+0
+0
+0
+0
+9
+7
+6
+6
+6
+6
+1
+9
+6
+5
+5
+0
+1
+4
+7
+7
+4
+3
+4
+4
+9
+2
+4
+9
+4
+3
+1
+2
+1
+0
+5
+9
+5
+3
+6
+2
+7
+1
+9
+4
+4
+3
+4
+3
+9
+0
+6
+6
+7
+7
+5
+3
+9
+2
+1
+0
+1
+4
+2
+4
+6
+6
+7
+5
+7
+0
+0
+0
+9
+4
+3
+1
+2
+5
+7
+3
+2
+9
+3
+4
+0
+2
+0
+3
+9
+2
+2
+5
+0
+5
+2
+7
+9
+1
+5
+2
+5
+4
+3
+3
+1
+9
+8
+7
+0
+1
+9
+5
+2
+3
+8
+8
+1
+2
+9
+1
+8
+6
+8
+8
+8
+8
+8
+6
+8
+7
+4
+8
+8
+8
+8
+8
+8
+4
+3
+2
+9
+4
+7
+4
+4
+0
+3
+1
+5
+9
+8
+6
+8
+3
+3
+8
+9
+8
+1
+8
+0
+5
+0
+4
+7
+6
+4
+8
+8
+1
+5
+0
+1
+9
+6
+1
+7
+6
+6
+6
+3
+0
+5
+0
+4
+2
+1
+7
+6
+9
+7
+0
+5
+7
+2
+5
+9
+9
+1
+2
+0
+0
+7
+3
+0
+5
+0
+8
+2
+4
+9
+3
+5
+9
+7
+7
+0
+5
+9
+7
+3
+2
+2
+2
+0
+0
+2
+3
+4
+9
+6
+2
+6
+6
+9
+9
+4
+9
+4
+5
+0
+5
+0
+9
+1
+4
+7
+1
+4
+7
+6
+6
+7
+2
+3
+4
+5
+6
+9
+5
+0
+5
+3
+7
+7
+4
+7
+7
+7
+7
+3
+2
+0
+9
+6
+1
+5
+6
+9
+5
+2
+4
+0
+6
+2
+7
+1
+6
+7
+5
+5
+3
+0
+6
+9
+7
+5
+1
+5
+2
+7
+3
+9
+1
+6
+1
+7
+7
+2
+5
+7
+7
+2
+0
+1
+4
+4
+7
+4
+1
+5
+2
+2
+5
+3
+4
+2
+7
+4
+9
+4
+2
+2
+4
+9
+4
+3
+9
+4
+7
+5
+3
+6
+5
+6
+4
+4
+0
+3
+3
+6
+9
+9
+2
+2
+4
+6
+0
+2
+0
+5
+7
+6
+8
+8
+8
+8
+8
+8
+8
+8
+8
+1
+8
+0
+1
+2
+8
+5
+6
+4
+1
+0
+3
+5
+2
+7
+7
+9
+7
+9
+3
+0
+4
+9
+6
+9
+9
+6
+2
+3
+6
+9
+5
+6
+9
+5
+0
+3
+4
+0
+7
+2
+4
+1
+8
+4
+7
+2
+1
+0
+2
+0
+8
+3
+1
+0
+5
+1
+7
+0
+2
+3
+4
+5
+7
+4
+9
+1
+6
+2
+0
+7
+4
+0
+7
+0
+3
+3
+2
+6
+6
+9
+6
+5
+3
+0
+6
+3
+9
+5
+4
+6
+2
+5
+6
+1
+0
+6
+5
+5
+1
+7
+3
+3
+9
+7
+5
+5
+3
+6
+1
+3
+9
+4
+0
+7
+0
+1
+5
+0
+5
+6
+1
+1
+2
+9
+3
+5
+9
+1
+7
+0
+1
+9
+1
+3
+4
+2
+0
+4
+0
+4
+3
+1
+7
+1
+4
+2
+4
+9
+0
+0
+4
+4
+6
+4
+9
+1
+3
+3
+1
+0
+4
+7
+9
+7
+7
+3
+9
+7
+0
+1
+0
+2
+9
+4
+1
+5
+2
+6
+5
+0
+6
+2
+5
+0
+5
+0
+1
+0
+5
+6
+7
+9
+7
+1
+9
+0
+6
+5
+0
+5
+2
+6
+9
+6
+6
+0
+7
+3
+1
+5
+9
+7
+2
+8
+8
+6
+6
+8
+8
+5
+8
+8
+5
+7
+7
+3
+0
+8
+8
+0
+8
+8
+8
+8
+8
+8
+8
+7
+8
+5
+8
+8
+8
+8
+4
+2
+5
+9
+3
+7
+0
+7
+4
+5
+2
+1
+3
+4
+1
+0
+6
+8
+8
+9
+1
+6
+6
+2
+0
+1
+0
+6
+9
+5
+4
+4
+8
+1
+4
+0
+0
+5
+7
+1
+8
+2
+1
+7
+7
+6
+6
+9
+8
+8
+2
+8
+5
+3
+8
+9
+0
+7
+7
+6
+6
+3
+5
+9
+1
+2
+5
+1
+2
+7
+7
+6
+9
+0
+2
+6
+3
+1
+2
+3
+9
+5
+9
+6
+3
+3
+7
+9
+4
+9
+4
+4
+5
+4
+4
+9
+2
+7
+4
+4
+0
+4
+3
+7
+9
+1
+5
+1
+4
+9
+4
+4
+9
+7
+7
+0
+5
+7
+4
+3
+9
+4
+6
+2
+3
+6
+5
+0
+9
+7
+5
+7
+1
+2
+6
+0
+5
+3
+0
+1
+6
+9
+2
+6
+1
+4
+7
+5
+6
+9
+3
+2
+9
+5
+9
+2
+0
+9
+0
+3
+2
+1
+7
+9
+9
+5
+3
+1
+0
+6
+0
+9
+6
+2
+3
+6
+5
+0
+5
+4
+9
+1
+3
+6
+7
+4
+1
+5
+4
+0
+0
+4
+1
+9
+7
+5
+6
+2
+4
+4
+2
+9
+2
+0
+9
+0
+7
+5
+3
+3
+7
+0
+0
+0
+3
+7
+4
+9
+4
+4
+5
+4
+6
+2
+2
+8
+8
+8
+8
+0
+8
+8
+2
+8
+6
+3
+8
+8
+7
+6
+8
+9
+4
+4
+7
+6
+6
+0
+6
+0
+6
+5
+6
+7
+5
+2
+3
+6
+3
+8
+1
+1
+4
+4
+5
+2
+3
+1
+0
+8
+1
+7
+1
+8
+9
+3
+8
+8
+8
+8
+8
+8
+9
+4
+5
+4
+8
+2
+7
+9
+5
+7
+9
+3
+6
+2
+4
+9
+1
+2
+3
+0
+7
+7
+2
+4
+6
+5
+2
+3
+6
+1
+5
+9
+1
+9
+9
+3
+2
+5
+7
+5
+9
+0
+3
+4
+1
+3
+0
+9
+9
+7
+4
+1
+0
+7
+2
+1
+0
+1
+3
+5
+4
+0
+1
+0
+5
+9
+1
+6
+2
+7
+6
+4
+5
+2
+5
+7
+3
+2
+4
+6
+6
+5
+0
+4
+0
+6
+2
+2
+9
+5
+0
+2
+0
+6
+1
+7
+7
+7
+7
+3
+3
+1
+0
+5
+6
+6
+6
+7
+7
+2
+7
+3
+9
+6
+5
+5
+3
+9
+3
+3
+9
+6
+1
+2
+4
+9
+0
+4
+2
+7
+5
+4
+1
+9
+4
+3
+2
+0
+4
+0
+4
+4
+6
+5
+0
+2
+7
+9
+9
+2
+2
+4
+0
+5
+2
+9
+5
+1
+2
+2
+7
+4
+7
+4
+9
+5
+9
+8
+8
+8
+8
+8
+1
+8
+8
+0
+8
+7
+8
+6
+6
+8
+8
+1
+7
+1
+2
+5
+9
+5
+1
+2
+6
+6
+1
+0
+9
+6
+3
+8
+5
+3
+0
+6
+0
+6
+7
+5
+8
+2
+9
+8
+5
+8
+0
+8
+8
+5
+8
+7
+5
+8
+1
+2
+4
+3
+8
+4
+2
+1
+8
+7
+3
+4
+9
+4
+5
+0
+0
+0
+3
+2
+4
+3
+4
+4
+1
+7
+3
+3
+9
+5
+4
+7
+8
+2
+6
+1
+0
+6
+0
+6
+5
+1
+3
+3
+4
+7
+2
+9
+7
+5
+3
+3
+1
+1
+5
+9
+4
+0
+0
+3
+8
+7
+7
+9
+2
+2
+1
+3
+0
+5
+6
+6
+6
+0
+7
+1
+7
+3
+1
+5
+9
+6
+6
+0
+6
+0
+4
+2
+9
+1
+6
+2
+5
+4
+1
+7
+7
+2
+3
+3
+1
+3
+2
+4
+9
+6
+1
+6
+7
+9
+4
+4
+0
+5
+0
+1
+3
+9
+7
+2
+4
+7
+0
+5
+7
+3
+5
+0
+1
+2
+4
+4
+3
+5
+6
+1
+9
+5
+0
+4
+3
+1
+3
+5
+9
+7
+6
+2
+0
+9
+9
+6
+7
+2
+4
+4
+5
+6
+0
+3
+6
+2
+5
+1
+3
+2
+1
+3
+0
+7
+0
+7
+7
+3
+2
+3
+5
+5
+2
+0
+0
+6
+6
+3
+6
+5
+7
+9
+9
+3
+6
+2
+2
+4
+1
+6
+9
+5
+7
+3
+4
+9
+6
+1
+9
+0
+1
+6
+4
+9
+2
+4
+5
+7
+3
+0
+7
+1
+4
+7
+5
+4
+3
+2
+2
+9
+5
+5
+1
+7
+7
+4
+5
+2
+9
+8
+8
+8
+8
+0
+5
+1
+2
+8
+8
+8
+8
+8
+3
+3
+8
+8
+8
+8
+8
+8
+8
+6
+9
+8
+8
+0
+8
+1
+8
+2
+9
+8
+0
+6
+6
+5
+4
+6
+5
+4
+6
+8
+8
+9
+0
+6
+9
+6
+5
+4
+8
+8
+3
+7
+9
+5
+2
+2
+4
+4
+3
+7
+4
+4
+7
+6
+6
+1
+9
+3
+1
+6
+4
+0
+2
+9
+5
+6
+7
+6
+6
+6
+4
+7
+9
+3
+1
+2
+2
+2
+5
+9
+9
+2
+6
+7
+0
+2
+0
+9
+3
+3
+2
+3
+7
+1
+7
+5
+7
+1
+4
+7
+7
+9
+1
+5
+3
+3
+0
+0
+1
+9
+7
+4
+6
+2
+3
+4
+1
+5
+9
+0
+3
+6
+3
+3
+6
+9
+9
+7
+5
+0
+6
+3
+4
+9
+4
+2
+1
+5
+7
+3
+2
+0
+9
+1
+4
+0
+3
+5
+6
+3
+9
+6
+4
+5
+2
+4
+7
+4
+9
+5
+1
+5
+3
+0
+1
+0
+9
+2
+0
+7
+7
+1
+5
+3
+6
+0
+1
+8
+8
+8
+8
+8
+8
+8
+8
+8
+1
+8
+8
+3
+8
+8
+7
+9
+3
+0
+9
+0
+4
+1
+0
+9
+3
+2
+9
+7
+5
+2
+7
+8
+9
+1
+2
+3
+1
+8
+0
+2
+0
+8
+3
+5
+6
+5
+8
+1
+2
+8
+8
+3
+6
+5
+4
+8
+5
+4
+1
+4
+0
+7
+8
+0
+1
+4
+5
+4
+7
+3
+6
+1
+9
+7
+4
+0
+4
+4
+5
+8
+5
+6
+0
+0
+7
+2
+1
+5
+9
+2
+7
+3
+5
+9
+4
+2
+7
+0
+3
+0
+5
+7
+9
+5
+2
+4
+3
+4
+2
+0
+9
+4
+9
+2
+1
+7
+5
+5
+4
+6
+6
+2
+5
+6
+3
+9
+2
+1
+4
+2
+5
+0
+7
+3
+2
+2
+1
+9
+1
+2
+3
+3
+5
+1
+4
+4
+3
+4
+2
+3
+5
+7
+1
+7
+4
+6
+4
+4
+6
+5
+0
+1
+4
+7
+1
+4
+2
+3
+6
+6
+6
+2
+0
+1
+4
+1
+6
+9
+0
+7
+2
+5
+6
+6
+5
+9
+1
+4
+3
+2
+0
+7
+7
+6
+0
+0
+3
+6
+2
+1
+5
+5
+9
+7
+4
+0
+3
+3
+4
+4
+9
+9
+3
+7
+7
+3
+0
+9
+9
+6
+6
+1
+3
+9
+0
+3
+7
+1
+4
+4
+2
+4
+6
+3
+9
+5
+7
+6
+1
+7
+2
+7
+1
+6
+6
+5
+6
+6
+5
+3
+9
+4
+1
+2
+3
+4
+7
+2
+5
+5
+1
+2
+9
+0
+1
+3
+2
+4
+5
+6
+6
+2
+7
+4
+0
+6
+6
+9
+3
+6
+2
+0
+6
+0
+4
+5
+9
+7
+3
+1
+7
+8
+1
+6
+8
+8
+3
+8
+5
+9
+7
+8
+0
+8
+8
+8
+8
+8
+8
+4
+8
+8
+2
+8
+1
+8
+8
+8
+8
+4
+1
+2
+5
+3
+8
+0
+0
+1
+0
+4
+2
+7
+6
+7
+7
+2
+0
+7
+8
+9
+2
+8
+1
+6
+6
+8
+6
+3
+7
+5
+7
+5
+3
+2
+3
+6
+9
+4
+6
+7
+7
+0
+2
+0
+9
+5
+1
+6
+6
+6
+1
+9
+9
+5
+9
+7
+5
+1
+3
+9
+9
+7
+1
+1
+3
+9
+9
+6
+6
+1
+7
+0
+5
+6
+9
+3
+0
+6
+2
+6
+0
+6
+5
+2
+9
+1
+7
+3
+3
+9
+4
+3
+2
+4
+1
+0
+5
+4
+3
+3
+1
+2
+1
+5
+3
+0
+3
+0
+7
+1
+2
+1
+7
+0
+9
+2
+5
+7
+5
+4
+2
+9
+3
+5
+6
+6
+4
+9
+1
+7
+9
+3
+5
+2
+0
+6
+4
+4
+6
+4
+7
+3
+7
+6
+6
+7
+5
+5
+2
+3
+1
+9
+2
+6
+0
+7
+7
+3
+5
+8
+0
+8
+8
+8
+8
+8
+8
+3
+9
+8
+0
+8
+8
+7
+8
+8
+8
+8
+8
+8
+4
+8
+8
+8
+9
+8
+8
+8
+6
+8
+0
+6
+0
+6
+4
+9
+3
+1
+8
+8
+1
+2
+1
+9
+7
+8
+2
+7
+8
+8
+0
+8
+0
+8
+4
+2
+4
+5
+8
+9
+5
+8
+0
+3
+4
+1
+8
+0
+9
+2
+5
+3
+7
+2
+4
+1
+9
+0
+7
+5
+8
+1
+2
+9
+6
+0
+9
+2
+6
+6
+1
+7
+2
+7
+7
+3
+6
+2
+1
+6
+9
+6
+3
+7
+5
+2
+7
+4
+0
+6
+2
+4
+1
+6
+2
+2
+9
+5
+4
+7
+7
+0
+7
+0
+2
+7
+3
+3
+4
+9
+0
+4
+0
+2
+7
+5
+3
+7
+4
+2
+5
+4
+0
+2
+5
+3
+1
+2
+5
+4
+0
+6
+0
+9
+6
+5
+2
+6
+4
+1
+9
+3
+0
+5
+2
+1
+3
+4
+1
+3
+1
+1
+3
+2
+0
+9
+9
+2
+5
+5
+3
+1
+0
+9
+6
+5
+7
+2
+5
+7
+6
+9
+3
+1
+5
+7
+1
+9
+5
+0
+3
+6
+7
+3
+4
+5
+6
+1
+3
+4
+6
+4
+5
+6
+2
+7
+3
+0
+5
+2
+2
+5
+4
+0
+2
+6
+4
+7
+4
+4
+7
+4
+5
+0
+3
+3
+1
+2
+9
+4
+3
+0
+5
+3
+7
+9
+2
+2
+4
+5
+4
+6
+5
+0
+5
+8
+8
+8
+8
+8
+8
+3
+8
+6
+8
+8
+8
+8
+8
+8
+8
+5
+0
+5
+3
+6
+5
+6
+7
+2
+2
+1
+3
+5
+1
+9
+9
+2
+8
+9
+3
+5
+7
+1
+0
+8
+1
+9
+3
+6
+8
+6
+5
+8
+8
+8
+8
+8
+8
+2
+8
+8
+8
+8
+3
+8
+8
+8
+8
+6
+6
+5
+9
+6
+1
+7
+4
+5
+4
+4
+9
+1
+3
+5
+8
+1
+8
+2
+0
+4
+0
+3
+7
+8
+8
+9
+9
+2
+4
+3
+0
+7
+1
+0
+7
+5
+2
+4
+0
+9
+5
+1
+9
+7
+6
+0
+4
+7
+5
+2
+9
+5
+3
+0
+1
+0
+6
+6
+2
+2
+5
+1
+6
+9
+0
+9
+9
+6
+2
+1
+6
+9
+7
+6
+0
+7
+0
+5
+3
+0
+4
+2
+1
+4
+0
+6
+2
+9
+7
+1
+5
+2
+4
+4
+0
+5
+4
+0
+3
+2
+7
+1
+6
+3
+1
+7
+1
+5
+3
+9
+4
+6
+9
+6
+6
+1
+3
+9
+6
+0
+5
+7
+7
+2
+3
+9
+1
+2
+0
+1
+5
+5
+1
+7
+3
+3
+2
+5
+0
+1
+0
+9
+3
+1
+5
+1
+0
+7
+0
+2
+5
+3
+6
+5
+1
+6
+4
+6
+2
+2
+8
+3
+8
+9
+5
+8
+8
+1
+2
+6
+6
+9
+8
+0
+8
+8
+8
+8
+8
+8
+4
+2
+0
+8
+0
+8
+8
+8
+8
+8
+8
+2
+3
+7
+5
+9
+2
+0
+4
+0
+4
+5
+0
+4
+7
+2
+5
+0
+8
+3
+7
+9
+8
+8
+8
+5
+3
+0
+2
+6
+6
+4
+9
+5
+7
+6
+2
+4
+5
+1
+3
+2
+1
+3
+5
+5
+4
+4
+3
+0
+7
+3
+9
+5
+4
+7
+7
+4
+5
+0
+9
+0
+8
+8
+1
+9
+3
+1
+2
+3
+1
+5
+1
+9
+3
+5
+9
+1
+5
+6
+6
+9
+3
+1
+7
+6
+6
+2
+4
+9
+3
+4
+1
+1
+7
+5
+2
+5
+9
+4
+3
+4
+5
+6
+0
+1
+9
+1
+4
+5
+2
+4
+7
+9
+0
+6
+4
+3
+4
+5
+1
+9
+5
+2
+3
+7
+0
+1
+4
+0
+9
+6
+5
+2
+0
+3
+4
+7
+2
+5
+7
+0
+5
+9
+1
+9
+9
+0
+1
+0
+7
+3
+5
+6
+7
+1
+6
+6
+1
+7
+2
+0
+4
+5
+3
+9
+0
+3
+2
+2
+1
+0
+5
+2
+9
+3
+7
+1
+4
+4
+3
+4
+4
+1
+9
+6
+6
+2
+3
+9
+7
+0
+1
+2
+5
+1
+4
+9
+6
+4
+2
+4
+7
+6
+6
+1
+5
+3
+4
+1
+2
+5
+6
+9
+9
+0
+5
+0
+4
+4
+1
+4
+3
+2
+2
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+8
+7
+8
+0
+8
+8
+5
+2
+0
+0
+5
+0
+5
+1
+3
+5
+9
+7
+6
+6
+2
+6
+8
+8
+9
+4
+7
+8
+8
+7
+2
+6
+5
+9
+8
+5
+0
+1
+8
+6
+9
+8
+8
+7
+6
+3
+8
+4
+4
+8
+4
+1
+5
+3
+4
+9
+2
+8
+0
+7
+9
+3
+3
+6
+4
+2
+2
+6
+9
+3
+2
+9
+8
+8
+6
+6
+1
+6
+7
+2
+6
+4
+8
+4
+4
+1
+6
+5
+3
+6
+7
+7
+0
+2
+5
+9
+3
+2
+1
+5
+9
+4
+2
+9
+5
+0
+7
+5
+9
+3
+3
+9
+7
+1
+0
+8
+9
+3
+4
+3
+2
+0
+0
+0
+7
+9
+1
+3
+3
+5
+6
+6
+9
+0
+7
+4
+3
+7
+4
+2
+9
+9
+6
+3
+6
+4
+6
+4
+4
+5
+7
+5
+7
+7
+9
+4
+6
+6
+4
+3
+5
+3
+2
+5
+9
+4
+7
+7
+5
+1
+3
+2
+9
+9
+5
+4
+1
+0
+9
+0
+5
+9
diff --git a/vdslib/src/tests/distribution/testdata/abovesplitbit.java.results b/vdslib/src/tests/distribution/testdata/abovesplitbit.java.results
new file mode 100644
index 00000000000..6fd944af3e9
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/abovesplitbit.java.results
@@ -0,0 +1,225 @@
+{
+ "cluster-state": "distributor:10",
+ "distribution": "redundancy 3\ninitial_redundancy 0\nensure_primary_persisted true\nready_copies 0\nactive_per_leaf_group false\ndistributor_auto_ownership_transfer_on_whole_group_down true\ngroup[0].index \"invalid\"\ngroup[0].name \"invalid\"\ngroup[0].capacity 1.0\ngroup[0].partitions \"*\"\ngroup[0].nodes[0].index 0\ngroup[0].nodes[0].retired false\ngroup[0].nodes[1].index 1\ngroup[0].nodes[1].retired false\ngroup[0].nodes[2].index 2\ngroup[0].nodes[2].retired false\ngroup[0].nodes[3].index 3\ngroup[0].nodes[3].retired false\ngroup[0].nodes[4].index 4\ngroup[0].nodes[4].retired false\ngroup[0].nodes[5].index 5\ngroup[0].nodes[5].retired false\ngroup[0].nodes[6].index 6\ngroup[0].nodes[6].retired false\ngroup[0].nodes[7].index 7\ngroup[0].nodes[7].retired false\ngroup[0].nodes[8].index 8\ngroup[0].nodes[8].retired false\ngroup[0].nodes[9].index 9\ngroup[0].nodes[9].retired false\ndisk_distribution MODULO_BID",
+ "node-type": "distributor",
+ "redundancy": 3,
+ "node-count": 10,
+ "up-states": "uim",
+ "result": [
+ {
+ "bucket": "400000000000edb4",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000edb4",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000edb4",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c0000000000edb4",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "500000000000edb4",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "540000000010edb4",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "580000000030edb4",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c0000000070edb4",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000f0edb4",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000f0edb4",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000f0edb4",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000004f0edb4",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "700000000cf0edb4",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "740000001cf0edb4",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "780000003cf0edb4",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c0000003cf0edb4",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000003cf0edb4",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "840000003cf0edb4",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "880000023cf0edb4",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8c0000023cf0edb4",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "9000000a3cf0edb4",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "9400001a3cf0edb4",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "9800003a3cf0edb4",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "9c00007a3cf0edb4",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "a000007a3cf0edb4",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "a400007a3cf0edb4",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "a800007a3cf0edb4",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "ac00007a3cf0edb4",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "b000007a3cf0edb4",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "b400107a3cf0edb4",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "b800107a3cf0edb4",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "bc00107a3cf0edb4",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c000107a3cf0edb4",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c401107a3cf0edb4",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c803107a3cf0edb4",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "cc03107a3cf0edb4",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "d00b107a3cf0edb4",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "d40b107a3cf0edb4",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "d82b107a3cf0edb4",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "dc6b107a3cf0edb4",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "e06b107a3cf0edb4",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "e56b107a3cf0edb4",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "eb6b107a3cf0edb4",
+ "nodes": [2],
+ "failure": "NONE"
+ }
+ ]
+} \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/distbit0.java.results b/vdslib/src/tests/distribution/testdata/distbit0.java.results
new file mode 100644
index 00000000000..67f0c69bf7f
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/distbit0.java.results
@@ -0,0 +1,510 @@
+{
+ "cluster-state": "bits:0 distributor:10",
+ "distribution": "redundancy 3\ninitial_redundancy 0\nensure_primary_persisted true\nready_copies 0\nactive_per_leaf_group false\ndistributor_auto_ownership_transfer_on_whole_group_down true\ngroup[0].index \"invalid\"\ngroup[0].name \"invalid\"\ngroup[0].capacity 1.0\ngroup[0].partitions \"*\"\ngroup[0].nodes[0].index 0\ngroup[0].nodes[0].retired false\ngroup[0].nodes[1].index 1\ngroup[0].nodes[1].retired false\ngroup[0].nodes[2].index 2\ngroup[0].nodes[2].retired false\ngroup[0].nodes[3].index 3\ngroup[0].nodes[3].retired false\ngroup[0].nodes[4].index 4\ngroup[0].nodes[4].retired false\ngroup[0].nodes[5].index 5\ngroup[0].nodes[5].retired false\ngroup[0].nodes[6].index 6\ngroup[0].nodes[6].retired false\ngroup[0].nodes[7].index 7\ngroup[0].nodes[7].retired false\ngroup[0].nodes[8].index 8\ngroup[0].nodes[8].retired false\ngroup[0].nodes[9].index 9\ngroup[0].nodes[9].retired false\ndisk_distribution MODULO_BID",
+ "node-type": "distributor",
+ "redundancy": 3,
+ "node-count": 10,
+ "up-states": "uim",
+ "result": [
+ {
+ "bucket": "0",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "9",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "a",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "b",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "d",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "e",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "f",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "10",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "11",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "12",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "13",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "14",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "15",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "16",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "17",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "18",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "19",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1a",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1b",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1d",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1e",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1f",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "20",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "21",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "22",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "23",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "24",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "25",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "26",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "27",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "28",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "29",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2a",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2b",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2d",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2e",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2f",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "30",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "31",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "32",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "33",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "34",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "35",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "36",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "37",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "38",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "39",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3a",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3b",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3d",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3e",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3f",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "41",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "42",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "43",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "44",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "45",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "46",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "47",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "48",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "49",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4a",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4b",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4d",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4e",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4f",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "50",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "51",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "52",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "53",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "54",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "55",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "56",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "57",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "58",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "59",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5a",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5b",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5d",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5e",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5f",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "60",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "61",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "62",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "63",
+ "nodes": [6],
+ "failure": "NONE"
+ }
+ ]
+} \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/distbit1.java.results b/vdslib/src/tests/distribution/testdata/distbit1.java.results
new file mode 100644
index 00000000000..56c9b89f038
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/distbit1.java.results
@@ -0,0 +1,510 @@
+{
+ "cluster-state": "bits:1 distributor:10",
+ "distribution": "redundancy 3\ninitial_redundancy 0\nensure_primary_persisted true\nready_copies 0\nactive_per_leaf_group false\ndistributor_auto_ownership_transfer_on_whole_group_down true\ngroup[0].index \"invalid\"\ngroup[0].name \"invalid\"\ngroup[0].capacity 1.0\ngroup[0].partitions \"*\"\ngroup[0].nodes[0].index 0\ngroup[0].nodes[0].retired false\ngroup[0].nodes[1].index 1\ngroup[0].nodes[1].retired false\ngroup[0].nodes[2].index 2\ngroup[0].nodes[2].retired false\ngroup[0].nodes[3].index 3\ngroup[0].nodes[3].retired false\ngroup[0].nodes[4].index 4\ngroup[0].nodes[4].retired false\ngroup[0].nodes[5].index 5\ngroup[0].nodes[5].retired false\ngroup[0].nodes[6].index 6\ngroup[0].nodes[6].retired false\ngroup[0].nodes[7].index 7\ngroup[0].nodes[7].retired false\ngroup[0].nodes[8].index 8\ngroup[0].nodes[8].retired false\ngroup[0].nodes[9].index 9\ngroup[0].nodes[9].retired false\ndisk_distribution MODULO_BID",
+ "node-type": "distributor",
+ "redundancy": 3,
+ "node-count": 10,
+ "up-states": "uim",
+ "result": [
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ }
+ ]
+} \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/distbit10.java.results b/vdslib/src/tests/distribution/testdata/distbit10.java.results
new file mode 100644
index 00000000000..1e79fea2c78
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/distbit10.java.results
@@ -0,0 +1,510 @@
+{
+ "cluster-state": "bits:10 distributor:10",
+ "distribution": "redundancy 3\ninitial_redundancy 0\nensure_primary_persisted true\nready_copies 0\nactive_per_leaf_group false\ndistributor_auto_ownership_transfer_on_whole_group_down true\ngroup[0].index \"invalid\"\ngroup[0].name \"invalid\"\ngroup[0].capacity 1.0\ngroup[0].partitions \"*\"\ngroup[0].nodes[0].index 0\ngroup[0].nodes[0].retired false\ngroup[0].nodes[1].index 1\ngroup[0].nodes[1].retired false\ngroup[0].nodes[2].index 2\ngroup[0].nodes[2].retired false\ngroup[0].nodes[3].index 3\ngroup[0].nodes[3].retired false\ngroup[0].nodes[4].index 4\ngroup[0].nodes[4].retired false\ngroup[0].nodes[5].index 5\ngroup[0].nodes[5].retired false\ngroup[0].nodes[6].index 6\ngroup[0].nodes[6].retired false\ngroup[0].nodes[7].index 7\ngroup[0].nodes[7].retired false\ngroup[0].nodes[8].index 8\ngroup[0].nodes[8].retired false\ngroup[0].nodes[9].index 9\ngroup[0].nodes[9].retired false\ndisk_distribution MODULO_BID",
+ "node-type": "distributor",
+ "redundancy": 3,
+ "node-count": 10,
+ "up-states": "uim",
+ "result": [
+ {
+ "bucket": "2800000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000008",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000009",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "280000000000000a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "280000000000000b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "280000000000000c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "280000000000000d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "280000000000000e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "280000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000010",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000011",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000012",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000014",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000015",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000016",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000017",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000018",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000019",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "280000000000001a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "280000000000001b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "280000000000001c",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "280000000000001d",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "280000000000001e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "280000000000001f",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000020",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000021",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000022",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000023",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000024",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000025",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000026",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000027",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000028",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000029",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "280000000000002a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "280000000000002b",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "280000000000002c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "280000000000002d",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "280000000000002e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "280000000000002f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000030",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000031",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000032",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000033",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000034",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000035",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000036",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000037",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000038",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000039",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "280000000000003a",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "280000000000003b",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "280000000000003c",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "280000000000003d",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "280000000000003e",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "280000000000003f",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000040",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000041",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000042",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000043",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000044",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000045",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000046",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000047",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000048",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000049",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "280000000000004a",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "280000000000004b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "280000000000004c",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "280000000000004d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "280000000000004e",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "280000000000004f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000050",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000051",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000052",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000053",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000054",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000055",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000056",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000057",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000058",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000059",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "280000000000005a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "280000000000005b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "280000000000005c",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "280000000000005d",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "280000000000005e",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "280000000000005f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000060",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000061",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000062",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2800000000000063",
+ "nodes": [9],
+ "failure": "NONE"
+ }
+ ]
+} \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/distbit11.java.results b/vdslib/src/tests/distribution/testdata/distbit11.java.results
new file mode 100644
index 00000000000..67a529fb9bc
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/distbit11.java.results
@@ -0,0 +1,510 @@
+{
+ "cluster-state": "bits:11 distributor:10",
+ "distribution": "redundancy 3\ninitial_redundancy 0\nensure_primary_persisted true\nready_copies 0\nactive_per_leaf_group false\ndistributor_auto_ownership_transfer_on_whole_group_down true\ngroup[0].index \"invalid\"\ngroup[0].name \"invalid\"\ngroup[0].capacity 1.0\ngroup[0].partitions \"*\"\ngroup[0].nodes[0].index 0\ngroup[0].nodes[0].retired false\ngroup[0].nodes[1].index 1\ngroup[0].nodes[1].retired false\ngroup[0].nodes[2].index 2\ngroup[0].nodes[2].retired false\ngroup[0].nodes[3].index 3\ngroup[0].nodes[3].retired false\ngroup[0].nodes[4].index 4\ngroup[0].nodes[4].retired false\ngroup[0].nodes[5].index 5\ngroup[0].nodes[5].retired false\ngroup[0].nodes[6].index 6\ngroup[0].nodes[6].retired false\ngroup[0].nodes[7].index 7\ngroup[0].nodes[7].retired false\ngroup[0].nodes[8].index 8\ngroup[0].nodes[8].retired false\ngroup[0].nodes[9].index 9\ngroup[0].nodes[9].retired false\ndisk_distribution MODULO_BID",
+ "node-type": "distributor",
+ "redundancy": 3,
+ "node-count": 10,
+ "up-states": "uim",
+ "result": [
+ {
+ "bucket": "2c00000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000008",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000009",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c0000000000000a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c0000000000000b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c0000000000000c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c0000000000000d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c0000000000000e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c0000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000010",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000011",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000012",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000014",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000015",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000016",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000017",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000018",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000019",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c0000000000001a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c0000000000001b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c0000000000001c",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c0000000000001d",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c0000000000001e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c0000000000001f",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000020",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000021",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000022",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000023",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000024",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000025",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000026",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000027",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000028",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000029",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c0000000000002a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c0000000000002b",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c0000000000002c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c0000000000002d",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c0000000000002e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c0000000000002f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000030",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000031",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000032",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000033",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000034",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000035",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000036",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000037",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000038",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000039",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c0000000000003a",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c0000000000003b",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c0000000000003c",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c0000000000003d",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c0000000000003e",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c0000000000003f",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000040",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000041",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000042",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000043",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000044",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000045",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000046",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000047",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000048",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000049",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c0000000000004a",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c0000000000004b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c0000000000004c",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c0000000000004d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c0000000000004e",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c0000000000004f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000050",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000051",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000052",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000053",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000054",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000055",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000056",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000057",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000058",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000059",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c0000000000005a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c0000000000005b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c0000000000005c",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c0000000000005d",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c0000000000005e",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c0000000000005f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000060",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000061",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000062",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2c00000000000063",
+ "nodes": [9],
+ "failure": "NONE"
+ }
+ ]
+} \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/distbit12.java.results b/vdslib/src/tests/distribution/testdata/distbit12.java.results
new file mode 100644
index 00000000000..6b06790f9bf
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/distbit12.java.results
@@ -0,0 +1,510 @@
+{
+ "cluster-state": "bits:12 distributor:10",
+ "distribution": "redundancy 3\ninitial_redundancy 0\nensure_primary_persisted true\nready_copies 0\nactive_per_leaf_group false\ndistributor_auto_ownership_transfer_on_whole_group_down true\ngroup[0].index \"invalid\"\ngroup[0].name \"invalid\"\ngroup[0].capacity 1.0\ngroup[0].partitions \"*\"\ngroup[0].nodes[0].index 0\ngroup[0].nodes[0].retired false\ngroup[0].nodes[1].index 1\ngroup[0].nodes[1].retired false\ngroup[0].nodes[2].index 2\ngroup[0].nodes[2].retired false\ngroup[0].nodes[3].index 3\ngroup[0].nodes[3].retired false\ngroup[0].nodes[4].index 4\ngroup[0].nodes[4].retired false\ngroup[0].nodes[5].index 5\ngroup[0].nodes[5].retired false\ngroup[0].nodes[6].index 6\ngroup[0].nodes[6].retired false\ngroup[0].nodes[7].index 7\ngroup[0].nodes[7].retired false\ngroup[0].nodes[8].index 8\ngroup[0].nodes[8].retired false\ngroup[0].nodes[9].index 9\ngroup[0].nodes[9].retired false\ndisk_distribution MODULO_BID",
+ "node-type": "distributor",
+ "redundancy": 3,
+ "node-count": 10,
+ "up-states": "uim",
+ "result": [
+ {
+ "bucket": "3000000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000008",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000009",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "300000000000000a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "300000000000000b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "300000000000000c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "300000000000000d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "300000000000000e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "300000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000010",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000011",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000012",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000014",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000015",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000016",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000017",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000018",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000019",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "300000000000001a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "300000000000001b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "300000000000001c",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "300000000000001d",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "300000000000001e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "300000000000001f",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000020",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000021",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000022",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000023",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000024",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000025",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000026",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000027",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000028",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000029",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "300000000000002a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "300000000000002b",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "300000000000002c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "300000000000002d",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "300000000000002e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "300000000000002f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000030",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000031",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000032",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000033",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000034",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000035",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000036",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000037",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000038",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000039",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "300000000000003a",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "300000000000003b",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "300000000000003c",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "300000000000003d",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "300000000000003e",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "300000000000003f",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000040",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000041",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000042",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000043",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000044",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000045",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000046",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000047",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000048",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000049",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "300000000000004a",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "300000000000004b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "300000000000004c",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "300000000000004d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "300000000000004e",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "300000000000004f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000050",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000051",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000052",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000053",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000054",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000055",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000056",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000057",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000058",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000059",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "300000000000005a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "300000000000005b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "300000000000005c",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "300000000000005d",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "300000000000005e",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "300000000000005f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000060",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000061",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000062",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3000000000000063",
+ "nodes": [9],
+ "failure": "NONE"
+ }
+ ]
+} \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/distbit13.java.results b/vdslib/src/tests/distribution/testdata/distbit13.java.results
new file mode 100644
index 00000000000..12e86a1b51c
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/distbit13.java.results
@@ -0,0 +1,510 @@
+{
+ "cluster-state": "bits:13 distributor:10",
+ "distribution": "redundancy 3\ninitial_redundancy 0\nensure_primary_persisted true\nready_copies 0\nactive_per_leaf_group false\ndistributor_auto_ownership_transfer_on_whole_group_down true\ngroup[0].index \"invalid\"\ngroup[0].name \"invalid\"\ngroup[0].capacity 1.0\ngroup[0].partitions \"*\"\ngroup[0].nodes[0].index 0\ngroup[0].nodes[0].retired false\ngroup[0].nodes[1].index 1\ngroup[0].nodes[1].retired false\ngroup[0].nodes[2].index 2\ngroup[0].nodes[2].retired false\ngroup[0].nodes[3].index 3\ngroup[0].nodes[3].retired false\ngroup[0].nodes[4].index 4\ngroup[0].nodes[4].retired false\ngroup[0].nodes[5].index 5\ngroup[0].nodes[5].retired false\ngroup[0].nodes[6].index 6\ngroup[0].nodes[6].retired false\ngroup[0].nodes[7].index 7\ngroup[0].nodes[7].retired false\ngroup[0].nodes[8].index 8\ngroup[0].nodes[8].retired false\ngroup[0].nodes[9].index 9\ngroup[0].nodes[9].retired false\ndisk_distribution MODULO_BID",
+ "node-type": "distributor",
+ "redundancy": 3,
+ "node-count": 10,
+ "up-states": "uim",
+ "result": [
+ {
+ "bucket": "3400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000008",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000009",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "340000000000000a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "340000000000000b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "340000000000000c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "340000000000000d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "340000000000000e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "340000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000010",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000011",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000012",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000014",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000015",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000016",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000017",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000018",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000019",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "340000000000001a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "340000000000001b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "340000000000001c",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "340000000000001d",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "340000000000001e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "340000000000001f",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000020",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000021",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000022",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000023",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000024",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000025",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000026",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000027",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000028",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000029",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "340000000000002a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "340000000000002b",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "340000000000002c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "340000000000002d",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "340000000000002e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "340000000000002f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000030",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000031",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000032",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000033",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000034",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000035",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000036",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000037",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000038",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000039",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "340000000000003a",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "340000000000003b",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "340000000000003c",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "340000000000003d",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "340000000000003e",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "340000000000003f",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000040",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000041",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000042",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000043",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000044",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000045",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000046",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000047",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000048",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000049",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "340000000000004a",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "340000000000004b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "340000000000004c",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "340000000000004d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "340000000000004e",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "340000000000004f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000050",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000051",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000052",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000053",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000054",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000055",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000056",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000057",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000058",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000059",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "340000000000005a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "340000000000005b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "340000000000005c",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "340000000000005d",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "340000000000005e",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "340000000000005f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000060",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000061",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000062",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3400000000000063",
+ "nodes": [9],
+ "failure": "NONE"
+ }
+ ]
+} \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/distbit14.java.results b/vdslib/src/tests/distribution/testdata/distbit14.java.results
new file mode 100644
index 00000000000..c966508c881
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/distbit14.java.results
@@ -0,0 +1,510 @@
+{
+ "cluster-state": "bits:14 distributor:10",
+ "distribution": "redundancy 3\ninitial_redundancy 0\nensure_primary_persisted true\nready_copies 0\nactive_per_leaf_group false\ndistributor_auto_ownership_transfer_on_whole_group_down true\ngroup[0].index \"invalid\"\ngroup[0].name \"invalid\"\ngroup[0].capacity 1.0\ngroup[0].partitions \"*\"\ngroup[0].nodes[0].index 0\ngroup[0].nodes[0].retired false\ngroup[0].nodes[1].index 1\ngroup[0].nodes[1].retired false\ngroup[0].nodes[2].index 2\ngroup[0].nodes[2].retired false\ngroup[0].nodes[3].index 3\ngroup[0].nodes[3].retired false\ngroup[0].nodes[4].index 4\ngroup[0].nodes[4].retired false\ngroup[0].nodes[5].index 5\ngroup[0].nodes[5].retired false\ngroup[0].nodes[6].index 6\ngroup[0].nodes[6].retired false\ngroup[0].nodes[7].index 7\ngroup[0].nodes[7].retired false\ngroup[0].nodes[8].index 8\ngroup[0].nodes[8].retired false\ngroup[0].nodes[9].index 9\ngroup[0].nodes[9].retired false\ndisk_distribution MODULO_BID",
+ "node-type": "distributor",
+ "redundancy": 3,
+ "node-count": 10,
+ "up-states": "uim",
+ "result": [
+ {
+ "bucket": "3800000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000008",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000009",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "380000000000000a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "380000000000000b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "380000000000000c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "380000000000000d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "380000000000000e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "380000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000010",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000011",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000012",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000014",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000015",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000016",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000017",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000018",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000019",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "380000000000001a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "380000000000001b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "380000000000001c",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "380000000000001d",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "380000000000001e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "380000000000001f",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000020",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000021",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000022",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000023",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000024",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000025",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000026",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000027",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000028",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000029",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "380000000000002a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "380000000000002b",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "380000000000002c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "380000000000002d",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "380000000000002e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "380000000000002f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000030",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000031",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000032",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000033",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000034",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000035",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000036",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000037",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000038",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000039",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "380000000000003a",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "380000000000003b",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "380000000000003c",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "380000000000003d",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "380000000000003e",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "380000000000003f",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000040",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000041",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000042",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000043",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000044",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000045",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000046",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000047",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000048",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000049",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "380000000000004a",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "380000000000004b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "380000000000004c",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "380000000000004d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "380000000000004e",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "380000000000004f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000050",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000051",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000052",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000053",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000054",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000055",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000056",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000057",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000058",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000059",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "380000000000005a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "380000000000005b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "380000000000005c",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "380000000000005d",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "380000000000005e",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "380000000000005f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000060",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000061",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000062",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3800000000000063",
+ "nodes": [9],
+ "failure": "NONE"
+ }
+ ]
+} \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/distbit15.java.results b/vdslib/src/tests/distribution/testdata/distbit15.java.results
new file mode 100644
index 00000000000..32838053818
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/distbit15.java.results
@@ -0,0 +1,510 @@
+{
+ "cluster-state": "bits:15 distributor:10",
+ "distribution": "redundancy 3\ninitial_redundancy 0\nensure_primary_persisted true\nready_copies 0\nactive_per_leaf_group false\ndistributor_auto_ownership_transfer_on_whole_group_down true\ngroup[0].index \"invalid\"\ngroup[0].name \"invalid\"\ngroup[0].capacity 1.0\ngroup[0].partitions \"*\"\ngroup[0].nodes[0].index 0\ngroup[0].nodes[0].retired false\ngroup[0].nodes[1].index 1\ngroup[0].nodes[1].retired false\ngroup[0].nodes[2].index 2\ngroup[0].nodes[2].retired false\ngroup[0].nodes[3].index 3\ngroup[0].nodes[3].retired false\ngroup[0].nodes[4].index 4\ngroup[0].nodes[4].retired false\ngroup[0].nodes[5].index 5\ngroup[0].nodes[5].retired false\ngroup[0].nodes[6].index 6\ngroup[0].nodes[6].retired false\ngroup[0].nodes[7].index 7\ngroup[0].nodes[7].retired false\ngroup[0].nodes[8].index 8\ngroup[0].nodes[8].retired false\ngroup[0].nodes[9].index 9\ngroup[0].nodes[9].retired false\ndisk_distribution MODULO_BID",
+ "node-type": "distributor",
+ "redundancy": 3,
+ "node-count": 10,
+ "up-states": "uim",
+ "result": [
+ {
+ "bucket": "3c00000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000008",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000009",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c0000000000000a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c0000000000000b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c0000000000000c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c0000000000000d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c0000000000000e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c0000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000010",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000011",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000012",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000014",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000015",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000016",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000017",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000018",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000019",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c0000000000001a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c0000000000001b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c0000000000001c",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c0000000000001d",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c0000000000001e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c0000000000001f",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000020",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000021",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000022",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000023",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000024",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000025",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000026",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000027",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000028",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000029",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c0000000000002a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c0000000000002b",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c0000000000002c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c0000000000002d",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c0000000000002e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c0000000000002f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000030",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000031",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000032",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000033",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000034",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000035",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000036",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000037",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000038",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000039",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c0000000000003a",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c0000000000003b",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c0000000000003c",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c0000000000003d",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c0000000000003e",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c0000000000003f",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000040",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000041",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000042",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000043",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000044",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000045",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000046",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000047",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000048",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000049",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c0000000000004a",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c0000000000004b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c0000000000004c",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c0000000000004d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c0000000000004e",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c0000000000004f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000050",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000051",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000052",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000053",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000054",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000055",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000056",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000057",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000058",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000059",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c0000000000005a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c0000000000005b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c0000000000005c",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c0000000000005d",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c0000000000005e",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c0000000000005f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000060",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000061",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000062",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "3c00000000000063",
+ "nodes": [9],
+ "failure": "NONE"
+ }
+ ]
+} \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/distbit16.java.results b/vdslib/src/tests/distribution/testdata/distbit16.java.results
new file mode 100644
index 00000000000..0688eef57d5
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/distbit16.java.results
@@ -0,0 +1,510 @@
+{
+ "cluster-state": "distributor:10",
+ "distribution": "redundancy 3\ninitial_redundancy 0\nensure_primary_persisted true\nready_copies 0\nactive_per_leaf_group false\ndistributor_auto_ownership_transfer_on_whole_group_down true\ngroup[0].index \"invalid\"\ngroup[0].name \"invalid\"\ngroup[0].capacity 1.0\ngroup[0].partitions \"*\"\ngroup[0].nodes[0].index 0\ngroup[0].nodes[0].retired false\ngroup[0].nodes[1].index 1\ngroup[0].nodes[1].retired false\ngroup[0].nodes[2].index 2\ngroup[0].nodes[2].retired false\ngroup[0].nodes[3].index 3\ngroup[0].nodes[3].retired false\ngroup[0].nodes[4].index 4\ngroup[0].nodes[4].retired false\ngroup[0].nodes[5].index 5\ngroup[0].nodes[5].retired false\ngroup[0].nodes[6].index 6\ngroup[0].nodes[6].retired false\ngroup[0].nodes[7].index 7\ngroup[0].nodes[7].retired false\ngroup[0].nodes[8].index 8\ngroup[0].nodes[8].retired false\ngroup[0].nodes[9].index 9\ngroup[0].nodes[9].retired false\ndisk_distribution MODULO_BID",
+ "node-type": "distributor",
+ "redundancy": 3,
+ "node-count": 10,
+ "up-states": "uim",
+ "result": [
+ {
+ "bucket": "4000000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000008",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000009",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000010",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000011",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000012",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000014",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000015",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000016",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000017",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000018",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000019",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001c",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001d",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001f",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000020",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000021",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000022",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000023",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000024",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000025",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000026",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000027",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000028",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000029",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000002a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000002b",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000002c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000002d",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000002e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000002f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000030",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000031",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000032",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000033",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000034",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000035",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000036",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000037",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000038",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000039",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000003a",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000003b",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000003c",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000003d",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000003e",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000003f",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000040",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000041",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000042",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000043",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000044",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000045",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000046",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000047",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000048",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000049",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000004a",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000004b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000004c",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000004d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000004e",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000004f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000050",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000051",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000052",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000053",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000054",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000055",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000056",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000057",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000058",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000059",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000005a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000005b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000005c",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000005d",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000005e",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000005f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000060",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000061",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000062",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000063",
+ "nodes": [9],
+ "failure": "NONE"
+ }
+ ]
+} \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/distbit17.java.results b/vdslib/src/tests/distribution/testdata/distbit17.java.results
new file mode 100644
index 00000000000..acb0fd5e2b3
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/distbit17.java.results
@@ -0,0 +1,510 @@
+{
+ "cluster-state": "bits:17 distributor:10",
+ "distribution": "redundancy 3\ninitial_redundancy 0\nensure_primary_persisted true\nready_copies 0\nactive_per_leaf_group false\ndistributor_auto_ownership_transfer_on_whole_group_down true\ngroup[0].index \"invalid\"\ngroup[0].name \"invalid\"\ngroup[0].capacity 1.0\ngroup[0].partitions \"*\"\ngroup[0].nodes[0].index 0\ngroup[0].nodes[0].retired false\ngroup[0].nodes[1].index 1\ngroup[0].nodes[1].retired false\ngroup[0].nodes[2].index 2\ngroup[0].nodes[2].retired false\ngroup[0].nodes[3].index 3\ngroup[0].nodes[3].retired false\ngroup[0].nodes[4].index 4\ngroup[0].nodes[4].retired false\ngroup[0].nodes[5].index 5\ngroup[0].nodes[5].retired false\ngroup[0].nodes[6].index 6\ngroup[0].nodes[6].retired false\ngroup[0].nodes[7].index 7\ngroup[0].nodes[7].retired false\ngroup[0].nodes[8].index 8\ngroup[0].nodes[8].retired false\ngroup[0].nodes[9].index 9\ngroup[0].nodes[9].retired false\ndisk_distribution MODULO_BID",
+ "node-type": "distributor",
+ "redundancy": 3,
+ "node-count": 10,
+ "up-states": "uim",
+ "result": [
+ {
+ "bucket": "4400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000008",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000009",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000000a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000000b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000000c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000000d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000000e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000010",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000011",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000012",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000014",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000015",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000016",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000017",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000018",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000019",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000001a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000001b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000001c",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000001d",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000001e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000001f",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000020",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000021",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000022",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000023",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000024",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000025",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000026",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000027",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000028",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000029",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000002a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000002b",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000002c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000002d",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000002e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000002f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000030",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000031",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000032",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000033",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000034",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000035",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000036",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000037",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000038",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000039",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000003a",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000003b",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000003c",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000003d",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000003e",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000003f",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000040",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000041",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000042",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000043",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000044",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000045",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000046",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000047",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000048",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000049",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000004a",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000004b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000004c",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000004d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000004e",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000004f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000050",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000051",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000052",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000053",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000054",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000055",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000056",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000057",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000058",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000059",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000005a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000005b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000005c",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000005d",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000005e",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000005f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000060",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000061",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000062",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000063",
+ "nodes": [9],
+ "failure": "NONE"
+ }
+ ]
+} \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/distbit18.java.results b/vdslib/src/tests/distribution/testdata/distbit18.java.results
new file mode 100644
index 00000000000..e94f0c6f550
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/distbit18.java.results
@@ -0,0 +1,510 @@
+{
+ "cluster-state": "bits:18 distributor:10",
+ "distribution": "redundancy 3\ninitial_redundancy 0\nensure_primary_persisted true\nready_copies 0\nactive_per_leaf_group false\ndistributor_auto_ownership_transfer_on_whole_group_down true\ngroup[0].index \"invalid\"\ngroup[0].name \"invalid\"\ngroup[0].capacity 1.0\ngroup[0].partitions \"*\"\ngroup[0].nodes[0].index 0\ngroup[0].nodes[0].retired false\ngroup[0].nodes[1].index 1\ngroup[0].nodes[1].retired false\ngroup[0].nodes[2].index 2\ngroup[0].nodes[2].retired false\ngroup[0].nodes[3].index 3\ngroup[0].nodes[3].retired false\ngroup[0].nodes[4].index 4\ngroup[0].nodes[4].retired false\ngroup[0].nodes[5].index 5\ngroup[0].nodes[5].retired false\ngroup[0].nodes[6].index 6\ngroup[0].nodes[6].retired false\ngroup[0].nodes[7].index 7\ngroup[0].nodes[7].retired false\ngroup[0].nodes[8].index 8\ngroup[0].nodes[8].retired false\ngroup[0].nodes[9].index 9\ngroup[0].nodes[9].retired false\ndisk_distribution MODULO_BID",
+ "node-type": "distributor",
+ "redundancy": 3,
+ "node-count": 10,
+ "up-states": "uim",
+ "result": [
+ {
+ "bucket": "4800000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000008",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000009",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000000a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000000b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000000c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000000d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000000e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000010",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000011",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000012",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000014",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000015",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000016",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000017",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000018",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000019",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000001a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000001b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000001c",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000001d",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000001e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000001f",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000020",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000021",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000022",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000023",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000024",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000025",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000026",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000027",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000028",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000029",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000002a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000002b",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000002c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000002d",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000002e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000002f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000030",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000031",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000032",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000033",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000034",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000035",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000036",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000037",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000038",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000039",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000003a",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000003b",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000003c",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000003d",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000003e",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000003f",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000040",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000041",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000042",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000043",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000044",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000045",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000046",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000047",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000048",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000049",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000004a",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000004b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000004c",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000004d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000004e",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000004f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000050",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000051",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000052",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000053",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000054",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000055",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000056",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000057",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000058",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000059",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000005a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000005b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000005c",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000005d",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000005e",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000005f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000060",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000061",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000062",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000063",
+ "nodes": [9],
+ "failure": "NONE"
+ }
+ ]
+} \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/distbit19.java.results b/vdslib/src/tests/distribution/testdata/distbit19.java.results
new file mode 100644
index 00000000000..81a367b02ad
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/distbit19.java.results
@@ -0,0 +1,510 @@
+{
+ "cluster-state": "bits:19 distributor:10",
+ "distribution": "redundancy 3\ninitial_redundancy 0\nensure_primary_persisted true\nready_copies 0\nactive_per_leaf_group false\ndistributor_auto_ownership_transfer_on_whole_group_down true\ngroup[0].index \"invalid\"\ngroup[0].name \"invalid\"\ngroup[0].capacity 1.0\ngroup[0].partitions \"*\"\ngroup[0].nodes[0].index 0\ngroup[0].nodes[0].retired false\ngroup[0].nodes[1].index 1\ngroup[0].nodes[1].retired false\ngroup[0].nodes[2].index 2\ngroup[0].nodes[2].retired false\ngroup[0].nodes[3].index 3\ngroup[0].nodes[3].retired false\ngroup[0].nodes[4].index 4\ngroup[0].nodes[4].retired false\ngroup[0].nodes[5].index 5\ngroup[0].nodes[5].retired false\ngroup[0].nodes[6].index 6\ngroup[0].nodes[6].retired false\ngroup[0].nodes[7].index 7\ngroup[0].nodes[7].retired false\ngroup[0].nodes[8].index 8\ngroup[0].nodes[8].retired false\ngroup[0].nodes[9].index 9\ngroup[0].nodes[9].retired false\ndisk_distribution MODULO_BID",
+ "node-type": "distributor",
+ "redundancy": 3,
+ "node-count": 10,
+ "up-states": "uim",
+ "result": [
+ {
+ "bucket": "4c00000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000008",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000009",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c0000000000000a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c0000000000000b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c0000000000000c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c0000000000000d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c0000000000000e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c0000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000010",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000011",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000012",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000014",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000015",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000016",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000017",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000018",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000019",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c0000000000001a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c0000000000001b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c0000000000001c",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c0000000000001d",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c0000000000001e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c0000000000001f",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000020",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000021",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000022",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000023",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000024",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000025",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000026",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000027",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000028",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000029",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c0000000000002a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c0000000000002b",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c0000000000002c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c0000000000002d",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c0000000000002e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c0000000000002f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000030",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000031",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000032",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000033",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000034",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000035",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000036",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000037",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000038",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000039",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c0000000000003a",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c0000000000003b",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c0000000000003c",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c0000000000003d",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c0000000000003e",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c0000000000003f",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000040",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000041",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000042",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000043",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000044",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000045",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000046",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000047",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000048",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000049",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c0000000000004a",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c0000000000004b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c0000000000004c",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c0000000000004d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c0000000000004e",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c0000000000004f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000050",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000051",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000052",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000053",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000054",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000055",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000056",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000057",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000058",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000059",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c0000000000005a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c0000000000005b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c0000000000005c",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c0000000000005d",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c0000000000005e",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c0000000000005f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000060",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000061",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000062",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c00000000000063",
+ "nodes": [9],
+ "failure": "NONE"
+ }
+ ]
+} \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/distbit2.java.results b/vdslib/src/tests/distribution/testdata/distbit2.java.results
new file mode 100644
index 00000000000..e34e5d45a9c
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/distbit2.java.results
@@ -0,0 +1,510 @@
+{
+ "cluster-state": "bits:2 distributor:10",
+ "distribution": "redundancy 3\ninitial_redundancy 0\nensure_primary_persisted true\nready_copies 0\nactive_per_leaf_group false\ndistributor_auto_ownership_transfer_on_whole_group_down true\ngroup[0].index \"invalid\"\ngroup[0].name \"invalid\"\ngroup[0].capacity 1.0\ngroup[0].partitions \"*\"\ngroup[0].nodes[0].index 0\ngroup[0].nodes[0].retired false\ngroup[0].nodes[1].index 1\ngroup[0].nodes[1].retired false\ngroup[0].nodes[2].index 2\ngroup[0].nodes[2].retired false\ngroup[0].nodes[3].index 3\ngroup[0].nodes[3].retired false\ngroup[0].nodes[4].index 4\ngroup[0].nodes[4].retired false\ngroup[0].nodes[5].index 5\ngroup[0].nodes[5].retired false\ngroup[0].nodes[6].index 6\ngroup[0].nodes[6].retired false\ngroup[0].nodes[7].index 7\ngroup[0].nodes[7].retired false\ngroup[0].nodes[8].index 8\ngroup[0].nodes[8].retired false\ngroup[0].nodes[9].index 9\ngroup[0].nodes[9].retired false\ndisk_distribution MODULO_BID",
+ "node-type": "distributor",
+ "redundancy": 3,
+ "node-count": 10,
+ "up-states": "uim",
+ "result": [
+ {
+ "bucket": "800000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ }
+ ]
+} \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/distbit20.java.results b/vdslib/src/tests/distribution/testdata/distbit20.java.results
new file mode 100644
index 00000000000..eeb14660b57
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/distbit20.java.results
@@ -0,0 +1,510 @@
+{
+ "cluster-state": "bits:20 distributor:10",
+ "distribution": "redundancy 3\ninitial_redundancy 0\nensure_primary_persisted true\nready_copies 0\nactive_per_leaf_group false\ndistributor_auto_ownership_transfer_on_whole_group_down true\ngroup[0].index \"invalid\"\ngroup[0].name \"invalid\"\ngroup[0].capacity 1.0\ngroup[0].partitions \"*\"\ngroup[0].nodes[0].index 0\ngroup[0].nodes[0].retired false\ngroup[0].nodes[1].index 1\ngroup[0].nodes[1].retired false\ngroup[0].nodes[2].index 2\ngroup[0].nodes[2].retired false\ngroup[0].nodes[3].index 3\ngroup[0].nodes[3].retired false\ngroup[0].nodes[4].index 4\ngroup[0].nodes[4].retired false\ngroup[0].nodes[5].index 5\ngroup[0].nodes[5].retired false\ngroup[0].nodes[6].index 6\ngroup[0].nodes[6].retired false\ngroup[0].nodes[7].index 7\ngroup[0].nodes[7].retired false\ngroup[0].nodes[8].index 8\ngroup[0].nodes[8].retired false\ngroup[0].nodes[9].index 9\ngroup[0].nodes[9].retired false\ndisk_distribution MODULO_BID",
+ "node-type": "distributor",
+ "redundancy": 3,
+ "node-count": 10,
+ "up-states": "uim",
+ "result": [
+ {
+ "bucket": "5000000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000008",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000009",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "500000000000000a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "500000000000000b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "500000000000000c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "500000000000000d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "500000000000000e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "500000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000010",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000011",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000012",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000014",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000015",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000016",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000017",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000018",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000019",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "500000000000001a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "500000000000001b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "500000000000001c",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "500000000000001d",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "500000000000001e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "500000000000001f",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000020",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000021",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000022",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000023",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000024",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000025",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000026",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000027",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000028",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000029",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "500000000000002a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "500000000000002b",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "500000000000002c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "500000000000002d",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "500000000000002e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "500000000000002f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000030",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000031",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000032",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000033",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000034",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000035",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000036",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000037",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000038",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000039",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "500000000000003a",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "500000000000003b",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "500000000000003c",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "500000000000003d",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "500000000000003e",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "500000000000003f",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000040",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000041",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000042",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000043",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000044",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000045",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000046",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000047",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000048",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000049",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "500000000000004a",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "500000000000004b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "500000000000004c",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "500000000000004d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "500000000000004e",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "500000000000004f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000050",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000051",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000052",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000053",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000054",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000055",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000056",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000057",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000058",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000059",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "500000000000005a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "500000000000005b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "500000000000005c",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "500000000000005d",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "500000000000005e",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "500000000000005f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000060",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000061",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000062",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5000000000000063",
+ "nodes": [9],
+ "failure": "NONE"
+ }
+ ]
+} \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/distbit21.java.results b/vdslib/src/tests/distribution/testdata/distbit21.java.results
new file mode 100644
index 00000000000..e14c3753583
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/distbit21.java.results
@@ -0,0 +1,510 @@
+{
+ "cluster-state": "bits:21 distributor:10",
+ "distribution": "redundancy 3\ninitial_redundancy 0\nensure_primary_persisted true\nready_copies 0\nactive_per_leaf_group false\ndistributor_auto_ownership_transfer_on_whole_group_down true\ngroup[0].index \"invalid\"\ngroup[0].name \"invalid\"\ngroup[0].capacity 1.0\ngroup[0].partitions \"*\"\ngroup[0].nodes[0].index 0\ngroup[0].nodes[0].retired false\ngroup[0].nodes[1].index 1\ngroup[0].nodes[1].retired false\ngroup[0].nodes[2].index 2\ngroup[0].nodes[2].retired false\ngroup[0].nodes[3].index 3\ngroup[0].nodes[3].retired false\ngroup[0].nodes[4].index 4\ngroup[0].nodes[4].retired false\ngroup[0].nodes[5].index 5\ngroup[0].nodes[5].retired false\ngroup[0].nodes[6].index 6\ngroup[0].nodes[6].retired false\ngroup[0].nodes[7].index 7\ngroup[0].nodes[7].retired false\ngroup[0].nodes[8].index 8\ngroup[0].nodes[8].retired false\ngroup[0].nodes[9].index 9\ngroup[0].nodes[9].retired false\ndisk_distribution MODULO_BID",
+ "node-type": "distributor",
+ "redundancy": 3,
+ "node-count": 10,
+ "up-states": "uim",
+ "result": [
+ {
+ "bucket": "5400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000008",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000009",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "540000000000000a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "540000000000000b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "540000000000000c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "540000000000000d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "540000000000000e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "540000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000010",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000011",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000012",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000014",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000015",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000016",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000017",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000018",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000019",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "540000000000001a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "540000000000001b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "540000000000001c",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "540000000000001d",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "540000000000001e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "540000000000001f",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000020",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000021",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000022",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000023",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000024",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000025",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000026",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000027",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000028",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000029",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "540000000000002a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "540000000000002b",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "540000000000002c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "540000000000002d",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "540000000000002e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "540000000000002f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000030",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000031",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000032",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000033",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000034",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000035",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000036",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000037",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000038",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000039",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "540000000000003a",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "540000000000003b",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "540000000000003c",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "540000000000003d",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "540000000000003e",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "540000000000003f",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000040",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000041",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000042",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000043",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000044",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000045",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000046",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000047",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000048",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000049",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "540000000000004a",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "540000000000004b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "540000000000004c",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "540000000000004d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "540000000000004e",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "540000000000004f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000050",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000051",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000052",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000053",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000054",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000055",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000056",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000057",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000058",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000059",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "540000000000005a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "540000000000005b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "540000000000005c",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "540000000000005d",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "540000000000005e",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "540000000000005f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000060",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000061",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000062",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5400000000000063",
+ "nodes": [9],
+ "failure": "NONE"
+ }
+ ]
+} \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/distbit22.java.results b/vdslib/src/tests/distribution/testdata/distbit22.java.results
new file mode 100644
index 00000000000..251894a9e2d
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/distbit22.java.results
@@ -0,0 +1,510 @@
+{
+ "cluster-state": "bits:22 distributor:10",
+ "distribution": "redundancy 3\ninitial_redundancy 0\nensure_primary_persisted true\nready_copies 0\nactive_per_leaf_group false\ndistributor_auto_ownership_transfer_on_whole_group_down true\ngroup[0].index \"invalid\"\ngroup[0].name \"invalid\"\ngroup[0].capacity 1.0\ngroup[0].partitions \"*\"\ngroup[0].nodes[0].index 0\ngroup[0].nodes[0].retired false\ngroup[0].nodes[1].index 1\ngroup[0].nodes[1].retired false\ngroup[0].nodes[2].index 2\ngroup[0].nodes[2].retired false\ngroup[0].nodes[3].index 3\ngroup[0].nodes[3].retired false\ngroup[0].nodes[4].index 4\ngroup[0].nodes[4].retired false\ngroup[0].nodes[5].index 5\ngroup[0].nodes[5].retired false\ngroup[0].nodes[6].index 6\ngroup[0].nodes[6].retired false\ngroup[0].nodes[7].index 7\ngroup[0].nodes[7].retired false\ngroup[0].nodes[8].index 8\ngroup[0].nodes[8].retired false\ngroup[0].nodes[9].index 9\ngroup[0].nodes[9].retired false\ndisk_distribution MODULO_BID",
+ "node-type": "distributor",
+ "redundancy": 3,
+ "node-count": 10,
+ "up-states": "uim",
+ "result": [
+ {
+ "bucket": "5800000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000008",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000009",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "580000000000000a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "580000000000000b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "580000000000000c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "580000000000000d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "580000000000000e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "580000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000010",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000011",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000012",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000014",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000015",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000016",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000017",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000018",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000019",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "580000000000001a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "580000000000001b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "580000000000001c",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "580000000000001d",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "580000000000001e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "580000000000001f",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000020",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000021",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000022",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000023",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000024",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000025",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000026",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000027",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000028",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000029",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "580000000000002a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "580000000000002b",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "580000000000002c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "580000000000002d",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "580000000000002e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "580000000000002f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000030",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000031",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000032",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000033",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000034",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000035",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000036",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000037",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000038",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000039",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "580000000000003a",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "580000000000003b",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "580000000000003c",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "580000000000003d",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "580000000000003e",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "580000000000003f",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000040",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000041",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000042",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000043",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000044",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000045",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000046",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000047",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000048",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000049",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "580000000000004a",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "580000000000004b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "580000000000004c",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "580000000000004d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "580000000000004e",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "580000000000004f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000050",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000051",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000052",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000053",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000054",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000055",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000056",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000057",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000058",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000059",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "580000000000005a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "580000000000005b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "580000000000005c",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "580000000000005d",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "580000000000005e",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "580000000000005f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000060",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000061",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000062",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5800000000000063",
+ "nodes": [9],
+ "failure": "NONE"
+ }
+ ]
+} \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/distbit23.java.results b/vdslib/src/tests/distribution/testdata/distbit23.java.results
new file mode 100644
index 00000000000..3904aa3c75d
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/distbit23.java.results
@@ -0,0 +1,510 @@
+{
+ "cluster-state": "bits:23 distributor:10",
+ "distribution": "redundancy 3\ninitial_redundancy 0\nensure_primary_persisted true\nready_copies 0\nactive_per_leaf_group false\ndistributor_auto_ownership_transfer_on_whole_group_down true\ngroup[0].index \"invalid\"\ngroup[0].name \"invalid\"\ngroup[0].capacity 1.0\ngroup[0].partitions \"*\"\ngroup[0].nodes[0].index 0\ngroup[0].nodes[0].retired false\ngroup[0].nodes[1].index 1\ngroup[0].nodes[1].retired false\ngroup[0].nodes[2].index 2\ngroup[0].nodes[2].retired false\ngroup[0].nodes[3].index 3\ngroup[0].nodes[3].retired false\ngroup[0].nodes[4].index 4\ngroup[0].nodes[4].retired false\ngroup[0].nodes[5].index 5\ngroup[0].nodes[5].retired false\ngroup[0].nodes[6].index 6\ngroup[0].nodes[6].retired false\ngroup[0].nodes[7].index 7\ngroup[0].nodes[7].retired false\ngroup[0].nodes[8].index 8\ngroup[0].nodes[8].retired false\ngroup[0].nodes[9].index 9\ngroup[0].nodes[9].retired false\ndisk_distribution MODULO_BID",
+ "node-type": "distributor",
+ "redundancy": 3,
+ "node-count": 10,
+ "up-states": "uim",
+ "result": [
+ {
+ "bucket": "5c00000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000008",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000009",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c0000000000000a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c0000000000000b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c0000000000000c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c0000000000000d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c0000000000000e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c0000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000010",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000011",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000012",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000014",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000015",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000016",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000017",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000018",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000019",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c0000000000001a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c0000000000001b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c0000000000001c",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c0000000000001d",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c0000000000001e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c0000000000001f",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000020",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000021",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000022",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000023",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000024",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000025",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000026",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000027",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000028",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000029",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c0000000000002a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c0000000000002b",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c0000000000002c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c0000000000002d",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c0000000000002e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c0000000000002f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000030",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000031",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000032",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000033",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000034",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000035",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000036",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000037",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000038",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000039",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c0000000000003a",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c0000000000003b",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c0000000000003c",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c0000000000003d",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c0000000000003e",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c0000000000003f",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000040",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000041",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000042",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000043",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000044",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000045",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000046",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000047",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000048",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000049",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c0000000000004a",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c0000000000004b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c0000000000004c",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c0000000000004d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c0000000000004e",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c0000000000004f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000050",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000051",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000052",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000053",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000054",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000055",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000056",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000057",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000058",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000059",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c0000000000005a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c0000000000005b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c0000000000005c",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c0000000000005d",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c0000000000005e",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c0000000000005f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000060",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000061",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000062",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c00000000000063",
+ "nodes": [9],
+ "failure": "NONE"
+ }
+ ]
+} \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/distbit24.java.results b/vdslib/src/tests/distribution/testdata/distbit24.java.results
new file mode 100644
index 00000000000..500cdcfaaef
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/distbit24.java.results
@@ -0,0 +1,510 @@
+{
+ "cluster-state": "bits:24 distributor:10",
+ "distribution": "redundancy 3\ninitial_redundancy 0\nensure_primary_persisted true\nready_copies 0\nactive_per_leaf_group false\ndistributor_auto_ownership_transfer_on_whole_group_down true\ngroup[0].index \"invalid\"\ngroup[0].name \"invalid\"\ngroup[0].capacity 1.0\ngroup[0].partitions \"*\"\ngroup[0].nodes[0].index 0\ngroup[0].nodes[0].retired false\ngroup[0].nodes[1].index 1\ngroup[0].nodes[1].retired false\ngroup[0].nodes[2].index 2\ngroup[0].nodes[2].retired false\ngroup[0].nodes[3].index 3\ngroup[0].nodes[3].retired false\ngroup[0].nodes[4].index 4\ngroup[0].nodes[4].retired false\ngroup[0].nodes[5].index 5\ngroup[0].nodes[5].retired false\ngroup[0].nodes[6].index 6\ngroup[0].nodes[6].retired false\ngroup[0].nodes[7].index 7\ngroup[0].nodes[7].retired false\ngroup[0].nodes[8].index 8\ngroup[0].nodes[8].retired false\ngroup[0].nodes[9].index 9\ngroup[0].nodes[9].retired false\ndisk_distribution MODULO_BID",
+ "node-type": "distributor",
+ "redundancy": 3,
+ "node-count": 10,
+ "up-states": "uim",
+ "result": [
+ {
+ "bucket": "6000000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000008",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000009",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "600000000000000a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "600000000000000b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "600000000000000c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "600000000000000d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "600000000000000e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "600000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000010",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000011",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000012",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000014",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000015",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000016",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000017",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000018",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000019",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "600000000000001a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "600000000000001b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "600000000000001c",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "600000000000001d",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "600000000000001e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "600000000000001f",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000020",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000021",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000022",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000023",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000024",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000025",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000026",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000027",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000028",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000029",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "600000000000002a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "600000000000002b",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "600000000000002c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "600000000000002d",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "600000000000002e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "600000000000002f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000030",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000031",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000032",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000033",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000034",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000035",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000036",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000037",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000038",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000039",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "600000000000003a",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "600000000000003b",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "600000000000003c",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "600000000000003d",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "600000000000003e",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "600000000000003f",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000040",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000041",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000042",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000043",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000044",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000045",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000046",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000047",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000048",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000049",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "600000000000004a",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "600000000000004b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "600000000000004c",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "600000000000004d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "600000000000004e",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "600000000000004f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000050",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000051",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000052",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000053",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000054",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000055",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000056",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000057",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000058",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000059",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "600000000000005a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "600000000000005b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "600000000000005c",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "600000000000005d",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "600000000000005e",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "600000000000005f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000060",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000061",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000062",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6000000000000063",
+ "nodes": [9],
+ "failure": "NONE"
+ }
+ ]
+} \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/distbit25.java.results b/vdslib/src/tests/distribution/testdata/distbit25.java.results
new file mode 100644
index 00000000000..2de23e10802
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/distbit25.java.results
@@ -0,0 +1,510 @@
+{
+ "cluster-state": "bits:25 distributor:10",
+ "distribution": "redundancy 3\ninitial_redundancy 0\nensure_primary_persisted true\nready_copies 0\nactive_per_leaf_group false\ndistributor_auto_ownership_transfer_on_whole_group_down true\ngroup[0].index \"invalid\"\ngroup[0].name \"invalid\"\ngroup[0].capacity 1.0\ngroup[0].partitions \"*\"\ngroup[0].nodes[0].index 0\ngroup[0].nodes[0].retired false\ngroup[0].nodes[1].index 1\ngroup[0].nodes[1].retired false\ngroup[0].nodes[2].index 2\ngroup[0].nodes[2].retired false\ngroup[0].nodes[3].index 3\ngroup[0].nodes[3].retired false\ngroup[0].nodes[4].index 4\ngroup[0].nodes[4].retired false\ngroup[0].nodes[5].index 5\ngroup[0].nodes[5].retired false\ngroup[0].nodes[6].index 6\ngroup[0].nodes[6].retired false\ngroup[0].nodes[7].index 7\ngroup[0].nodes[7].retired false\ngroup[0].nodes[8].index 8\ngroup[0].nodes[8].retired false\ngroup[0].nodes[9].index 9\ngroup[0].nodes[9].retired false\ndisk_distribution MODULO_BID",
+ "node-type": "distributor",
+ "redundancy": 3,
+ "node-count": 10,
+ "up-states": "uim",
+ "result": [
+ {
+ "bucket": "6400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000008",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000009",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "640000000000000a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "640000000000000b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "640000000000000c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "640000000000000d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "640000000000000e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "640000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000010",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000011",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000012",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000014",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000015",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000016",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000017",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000018",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000019",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "640000000000001a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "640000000000001b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "640000000000001c",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "640000000000001d",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "640000000000001e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "640000000000001f",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000020",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000021",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000022",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000023",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000024",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000025",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000026",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000027",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000028",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000029",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "640000000000002a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "640000000000002b",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "640000000000002c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "640000000000002d",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "640000000000002e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "640000000000002f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000030",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000031",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000032",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000033",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000034",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000035",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000036",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000037",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000038",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000039",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "640000000000003a",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "640000000000003b",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "640000000000003c",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "640000000000003d",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "640000000000003e",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "640000000000003f",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000040",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000041",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000042",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000043",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000044",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000045",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000046",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000047",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000048",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000049",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "640000000000004a",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "640000000000004b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "640000000000004c",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "640000000000004d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "640000000000004e",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "640000000000004f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000050",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000051",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000052",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000053",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000054",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000055",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000056",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000057",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000058",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000059",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "640000000000005a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "640000000000005b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "640000000000005c",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "640000000000005d",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "640000000000005e",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "640000000000005f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000060",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000061",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000062",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6400000000000063",
+ "nodes": [9],
+ "failure": "NONE"
+ }
+ ]
+} \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/distbit26.java.results b/vdslib/src/tests/distribution/testdata/distbit26.java.results
new file mode 100644
index 00000000000..02faf3d8da5
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/distbit26.java.results
@@ -0,0 +1,510 @@
+{
+ "cluster-state": "bits:26 distributor:10",
+ "distribution": "redundancy 3\ninitial_redundancy 0\nensure_primary_persisted true\nready_copies 0\nactive_per_leaf_group false\ndistributor_auto_ownership_transfer_on_whole_group_down true\ngroup[0].index \"invalid\"\ngroup[0].name \"invalid\"\ngroup[0].capacity 1.0\ngroup[0].partitions \"*\"\ngroup[0].nodes[0].index 0\ngroup[0].nodes[0].retired false\ngroup[0].nodes[1].index 1\ngroup[0].nodes[1].retired false\ngroup[0].nodes[2].index 2\ngroup[0].nodes[2].retired false\ngroup[0].nodes[3].index 3\ngroup[0].nodes[3].retired false\ngroup[0].nodes[4].index 4\ngroup[0].nodes[4].retired false\ngroup[0].nodes[5].index 5\ngroup[0].nodes[5].retired false\ngroup[0].nodes[6].index 6\ngroup[0].nodes[6].retired false\ngroup[0].nodes[7].index 7\ngroup[0].nodes[7].retired false\ngroup[0].nodes[8].index 8\ngroup[0].nodes[8].retired false\ngroup[0].nodes[9].index 9\ngroup[0].nodes[9].retired false\ndisk_distribution MODULO_BID",
+ "node-type": "distributor",
+ "redundancy": 3,
+ "node-count": 10,
+ "up-states": "uim",
+ "result": [
+ {
+ "bucket": "6800000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000008",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000009",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "680000000000000a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "680000000000000b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "680000000000000c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "680000000000000d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "680000000000000e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "680000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000010",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000011",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000012",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000014",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000015",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000016",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000017",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000018",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000019",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "680000000000001a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "680000000000001b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "680000000000001c",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "680000000000001d",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "680000000000001e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "680000000000001f",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000020",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000021",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000022",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000023",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000024",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000025",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000026",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000027",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000028",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000029",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "680000000000002a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "680000000000002b",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "680000000000002c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "680000000000002d",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "680000000000002e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "680000000000002f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000030",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000031",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000032",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000033",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000034",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000035",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000036",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000037",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000038",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000039",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "680000000000003a",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "680000000000003b",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "680000000000003c",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "680000000000003d",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "680000000000003e",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "680000000000003f",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000040",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000041",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000042",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000043",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000044",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000045",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000046",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000047",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000048",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000049",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "680000000000004a",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "680000000000004b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "680000000000004c",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "680000000000004d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "680000000000004e",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "680000000000004f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000050",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000051",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000052",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000053",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000054",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000055",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000056",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000057",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000058",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000059",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "680000000000005a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "680000000000005b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "680000000000005c",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "680000000000005d",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "680000000000005e",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "680000000000005f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000060",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000061",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000062",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6800000000000063",
+ "nodes": [9],
+ "failure": "NONE"
+ }
+ ]
+} \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/distbit27.java.results b/vdslib/src/tests/distribution/testdata/distbit27.java.results
new file mode 100644
index 00000000000..1131247d201
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/distbit27.java.results
@@ -0,0 +1,510 @@
+{
+ "cluster-state": "bits:27 distributor:10",
+ "distribution": "redundancy 3\ninitial_redundancy 0\nensure_primary_persisted true\nready_copies 0\nactive_per_leaf_group false\ndistributor_auto_ownership_transfer_on_whole_group_down true\ngroup[0].index \"invalid\"\ngroup[0].name \"invalid\"\ngroup[0].capacity 1.0\ngroup[0].partitions \"*\"\ngroup[0].nodes[0].index 0\ngroup[0].nodes[0].retired false\ngroup[0].nodes[1].index 1\ngroup[0].nodes[1].retired false\ngroup[0].nodes[2].index 2\ngroup[0].nodes[2].retired false\ngroup[0].nodes[3].index 3\ngroup[0].nodes[3].retired false\ngroup[0].nodes[4].index 4\ngroup[0].nodes[4].retired false\ngroup[0].nodes[5].index 5\ngroup[0].nodes[5].retired false\ngroup[0].nodes[6].index 6\ngroup[0].nodes[6].retired false\ngroup[0].nodes[7].index 7\ngroup[0].nodes[7].retired false\ngroup[0].nodes[8].index 8\ngroup[0].nodes[8].retired false\ngroup[0].nodes[9].index 9\ngroup[0].nodes[9].retired false\ndisk_distribution MODULO_BID",
+ "node-type": "distributor",
+ "redundancy": 3,
+ "node-count": 10,
+ "up-states": "uim",
+ "result": [
+ {
+ "bucket": "6c00000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000008",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000009",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c0000000000000a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c0000000000000b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c0000000000000c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c0000000000000d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c0000000000000e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c0000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000010",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000011",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000012",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000014",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000015",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000016",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000017",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000018",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000019",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c0000000000001a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c0000000000001b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c0000000000001c",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c0000000000001d",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c0000000000001e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c0000000000001f",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000020",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000021",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000022",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000023",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000024",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000025",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000026",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000027",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000028",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000029",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c0000000000002a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c0000000000002b",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c0000000000002c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c0000000000002d",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c0000000000002e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c0000000000002f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000030",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000031",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000032",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000033",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000034",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000035",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000036",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000037",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000038",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000039",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c0000000000003a",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c0000000000003b",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c0000000000003c",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c0000000000003d",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c0000000000003e",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c0000000000003f",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000040",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000041",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000042",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000043",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000044",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000045",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000046",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000047",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000048",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000049",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c0000000000004a",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c0000000000004b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c0000000000004c",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c0000000000004d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c0000000000004e",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c0000000000004f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000050",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000051",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000052",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000053",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000054",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000055",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000056",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000057",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000058",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000059",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c0000000000005a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c0000000000005b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c0000000000005c",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c0000000000005d",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c0000000000005e",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c0000000000005f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000060",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000061",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000062",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c00000000000063",
+ "nodes": [9],
+ "failure": "NONE"
+ }
+ ]
+} \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/distbit28.java.results b/vdslib/src/tests/distribution/testdata/distbit28.java.results
new file mode 100644
index 00000000000..733aafe0b7e
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/distbit28.java.results
@@ -0,0 +1,510 @@
+{
+ "cluster-state": "bits:28 distributor:10",
+ "distribution": "redundancy 3\ninitial_redundancy 0\nensure_primary_persisted true\nready_copies 0\nactive_per_leaf_group false\ndistributor_auto_ownership_transfer_on_whole_group_down true\ngroup[0].index \"invalid\"\ngroup[0].name \"invalid\"\ngroup[0].capacity 1.0\ngroup[0].partitions \"*\"\ngroup[0].nodes[0].index 0\ngroup[0].nodes[0].retired false\ngroup[0].nodes[1].index 1\ngroup[0].nodes[1].retired false\ngroup[0].nodes[2].index 2\ngroup[0].nodes[2].retired false\ngroup[0].nodes[3].index 3\ngroup[0].nodes[3].retired false\ngroup[0].nodes[4].index 4\ngroup[0].nodes[4].retired false\ngroup[0].nodes[5].index 5\ngroup[0].nodes[5].retired false\ngroup[0].nodes[6].index 6\ngroup[0].nodes[6].retired false\ngroup[0].nodes[7].index 7\ngroup[0].nodes[7].retired false\ngroup[0].nodes[8].index 8\ngroup[0].nodes[8].retired false\ngroup[0].nodes[9].index 9\ngroup[0].nodes[9].retired false\ndisk_distribution MODULO_BID",
+ "node-type": "distributor",
+ "redundancy": 3,
+ "node-count": 10,
+ "up-states": "uim",
+ "result": [
+ {
+ "bucket": "7000000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000008",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000009",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "700000000000000a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "700000000000000b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "700000000000000c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "700000000000000d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "700000000000000e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "700000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000010",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000011",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000012",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000014",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000015",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000016",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000017",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000018",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000019",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "700000000000001a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "700000000000001b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "700000000000001c",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "700000000000001d",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "700000000000001e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "700000000000001f",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000020",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000021",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000022",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000023",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000024",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000025",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000026",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000027",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000028",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000029",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "700000000000002a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "700000000000002b",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "700000000000002c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "700000000000002d",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "700000000000002e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "700000000000002f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000030",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000031",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000032",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000033",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000034",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000035",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000036",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000037",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000038",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000039",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "700000000000003a",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "700000000000003b",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "700000000000003c",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "700000000000003d",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "700000000000003e",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "700000000000003f",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000040",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000041",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000042",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000043",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000044",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000045",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000046",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000047",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000048",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000049",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "700000000000004a",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "700000000000004b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "700000000000004c",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "700000000000004d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "700000000000004e",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "700000000000004f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000050",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000051",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000052",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000053",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000054",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000055",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000056",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000057",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000058",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000059",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "700000000000005a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "700000000000005b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "700000000000005c",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "700000000000005d",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "700000000000005e",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "700000000000005f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000060",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000061",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000062",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7000000000000063",
+ "nodes": [9],
+ "failure": "NONE"
+ }
+ ]
+} \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/distbit29.java.results b/vdslib/src/tests/distribution/testdata/distbit29.java.results
new file mode 100644
index 00000000000..52071433727
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/distbit29.java.results
@@ -0,0 +1,510 @@
+{
+ "cluster-state": "bits:29 distributor:10",
+ "distribution": "redundancy 3\ninitial_redundancy 0\nensure_primary_persisted true\nready_copies 0\nactive_per_leaf_group false\ndistributor_auto_ownership_transfer_on_whole_group_down true\ngroup[0].index \"invalid\"\ngroup[0].name \"invalid\"\ngroup[0].capacity 1.0\ngroup[0].partitions \"*\"\ngroup[0].nodes[0].index 0\ngroup[0].nodes[0].retired false\ngroup[0].nodes[1].index 1\ngroup[0].nodes[1].retired false\ngroup[0].nodes[2].index 2\ngroup[0].nodes[2].retired false\ngroup[0].nodes[3].index 3\ngroup[0].nodes[3].retired false\ngroup[0].nodes[4].index 4\ngroup[0].nodes[4].retired false\ngroup[0].nodes[5].index 5\ngroup[0].nodes[5].retired false\ngroup[0].nodes[6].index 6\ngroup[0].nodes[6].retired false\ngroup[0].nodes[7].index 7\ngroup[0].nodes[7].retired false\ngroup[0].nodes[8].index 8\ngroup[0].nodes[8].retired false\ngroup[0].nodes[9].index 9\ngroup[0].nodes[9].retired false\ndisk_distribution MODULO_BID",
+ "node-type": "distributor",
+ "redundancy": 3,
+ "node-count": 10,
+ "up-states": "uim",
+ "result": [
+ {
+ "bucket": "7400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000008",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000009",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "740000000000000a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "740000000000000b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "740000000000000c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "740000000000000d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "740000000000000e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "740000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000010",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000011",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000012",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000014",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000015",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000016",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000017",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000018",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000019",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "740000000000001a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "740000000000001b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "740000000000001c",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "740000000000001d",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "740000000000001e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "740000000000001f",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000020",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000021",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000022",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000023",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000024",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000025",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000026",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000027",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000028",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000029",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "740000000000002a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "740000000000002b",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "740000000000002c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "740000000000002d",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "740000000000002e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "740000000000002f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000030",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000031",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000032",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000033",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000034",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000035",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000036",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000037",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000038",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000039",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "740000000000003a",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "740000000000003b",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "740000000000003c",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "740000000000003d",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "740000000000003e",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "740000000000003f",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000040",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000041",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000042",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000043",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000044",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000045",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000046",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000047",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000048",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000049",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "740000000000004a",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "740000000000004b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "740000000000004c",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "740000000000004d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "740000000000004e",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "740000000000004f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000050",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000051",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000052",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000053",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000054",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000055",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000056",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000057",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000058",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000059",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "740000000000005a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "740000000000005b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "740000000000005c",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "740000000000005d",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "740000000000005e",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "740000000000005f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000060",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000061",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000062",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7400000000000063",
+ "nodes": [9],
+ "failure": "NONE"
+ }
+ ]
+} \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/distbit3.java.results b/vdslib/src/tests/distribution/testdata/distbit3.java.results
new file mode 100644
index 00000000000..3d79ad6896c
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/distbit3.java.results
@@ -0,0 +1,510 @@
+{
+ "cluster-state": "bits:3 distributor:10",
+ "distribution": "redundancy 3\ninitial_redundancy 0\nensure_primary_persisted true\nready_copies 0\nactive_per_leaf_group false\ndistributor_auto_ownership_transfer_on_whole_group_down true\ngroup[0].index \"invalid\"\ngroup[0].name \"invalid\"\ngroup[0].capacity 1.0\ngroup[0].partitions \"*\"\ngroup[0].nodes[0].index 0\ngroup[0].nodes[0].retired false\ngroup[0].nodes[1].index 1\ngroup[0].nodes[1].retired false\ngroup[0].nodes[2].index 2\ngroup[0].nodes[2].retired false\ngroup[0].nodes[3].index 3\ngroup[0].nodes[3].retired false\ngroup[0].nodes[4].index 4\ngroup[0].nodes[4].retired false\ngroup[0].nodes[5].index 5\ngroup[0].nodes[5].retired false\ngroup[0].nodes[6].index 6\ngroup[0].nodes[6].retired false\ngroup[0].nodes[7].index 7\ngroup[0].nodes[7].retired false\ngroup[0].nodes[8].index 8\ngroup[0].nodes[8].retired false\ngroup[0].nodes[9].index 9\ngroup[0].nodes[9].retired false\ndisk_distribution MODULO_BID",
+ "node-type": "distributor",
+ "redundancy": 3,
+ "node-count": 10,
+ "up-states": "uim",
+ "result": [
+ {
+ "bucket": "c00000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ }
+ ]
+} \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/distbit30.java.results b/vdslib/src/tests/distribution/testdata/distbit30.java.results
new file mode 100644
index 00000000000..c61e4781b26
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/distbit30.java.results
@@ -0,0 +1,510 @@
+{
+ "cluster-state": "bits:30 distributor:10",
+ "distribution": "redundancy 3\ninitial_redundancy 0\nensure_primary_persisted true\nready_copies 0\nactive_per_leaf_group false\ndistributor_auto_ownership_transfer_on_whole_group_down true\ngroup[0].index \"invalid\"\ngroup[0].name \"invalid\"\ngroup[0].capacity 1.0\ngroup[0].partitions \"*\"\ngroup[0].nodes[0].index 0\ngroup[0].nodes[0].retired false\ngroup[0].nodes[1].index 1\ngroup[0].nodes[1].retired false\ngroup[0].nodes[2].index 2\ngroup[0].nodes[2].retired false\ngroup[0].nodes[3].index 3\ngroup[0].nodes[3].retired false\ngroup[0].nodes[4].index 4\ngroup[0].nodes[4].retired false\ngroup[0].nodes[5].index 5\ngroup[0].nodes[5].retired false\ngroup[0].nodes[6].index 6\ngroup[0].nodes[6].retired false\ngroup[0].nodes[7].index 7\ngroup[0].nodes[7].retired false\ngroup[0].nodes[8].index 8\ngroup[0].nodes[8].retired false\ngroup[0].nodes[9].index 9\ngroup[0].nodes[9].retired false\ndisk_distribution MODULO_BID",
+ "node-type": "distributor",
+ "redundancy": 3,
+ "node-count": 10,
+ "up-states": "uim",
+ "result": [
+ {
+ "bucket": "7800000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000008",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000009",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "780000000000000a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "780000000000000b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "780000000000000c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "780000000000000d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "780000000000000e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "780000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000010",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000011",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000012",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000014",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000015",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000016",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000017",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000018",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000019",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "780000000000001a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "780000000000001b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "780000000000001c",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "780000000000001d",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "780000000000001e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "780000000000001f",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000020",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000021",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000022",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000023",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000024",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000025",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000026",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000027",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000028",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000029",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "780000000000002a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "780000000000002b",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "780000000000002c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "780000000000002d",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "780000000000002e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "780000000000002f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000030",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000031",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000032",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000033",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000034",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000035",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000036",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000037",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000038",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000039",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "780000000000003a",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "780000000000003b",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "780000000000003c",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "780000000000003d",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "780000000000003e",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "780000000000003f",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000040",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000041",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000042",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000043",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000044",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000045",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000046",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000047",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000048",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000049",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "780000000000004a",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "780000000000004b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "780000000000004c",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "780000000000004d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "780000000000004e",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "780000000000004f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000050",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000051",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000052",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000053",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000054",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000055",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000056",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000057",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000058",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000059",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "780000000000005a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "780000000000005b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "780000000000005c",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "780000000000005d",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "780000000000005e",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "780000000000005f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000060",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000061",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000062",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7800000000000063",
+ "nodes": [9],
+ "failure": "NONE"
+ }
+ ]
+} \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/distbit31.java.results b/vdslib/src/tests/distribution/testdata/distbit31.java.results
new file mode 100644
index 00000000000..4cba926f657
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/distbit31.java.results
@@ -0,0 +1,510 @@
+{
+ "cluster-state": "bits:31 distributor:10",
+ "distribution": "redundancy 3\ninitial_redundancy 0\nensure_primary_persisted true\nready_copies 0\nactive_per_leaf_group false\ndistributor_auto_ownership_transfer_on_whole_group_down true\ngroup[0].index \"invalid\"\ngroup[0].name \"invalid\"\ngroup[0].capacity 1.0\ngroup[0].partitions \"*\"\ngroup[0].nodes[0].index 0\ngroup[0].nodes[0].retired false\ngroup[0].nodes[1].index 1\ngroup[0].nodes[1].retired false\ngroup[0].nodes[2].index 2\ngroup[0].nodes[2].retired false\ngroup[0].nodes[3].index 3\ngroup[0].nodes[3].retired false\ngroup[0].nodes[4].index 4\ngroup[0].nodes[4].retired false\ngroup[0].nodes[5].index 5\ngroup[0].nodes[5].retired false\ngroup[0].nodes[6].index 6\ngroup[0].nodes[6].retired false\ngroup[0].nodes[7].index 7\ngroup[0].nodes[7].retired false\ngroup[0].nodes[8].index 8\ngroup[0].nodes[8].retired false\ngroup[0].nodes[9].index 9\ngroup[0].nodes[9].retired false\ndisk_distribution MODULO_BID",
+ "node-type": "distributor",
+ "redundancy": 3,
+ "node-count": 10,
+ "up-states": "uim",
+ "result": [
+ {
+ "bucket": "7c00000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000008",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000009",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c0000000000000a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c0000000000000b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c0000000000000c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c0000000000000d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c0000000000000e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c0000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000010",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000011",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000012",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000014",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000015",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000016",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000017",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000018",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000019",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c0000000000001a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c0000000000001b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c0000000000001c",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c0000000000001d",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c0000000000001e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c0000000000001f",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000020",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000021",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000022",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000023",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000024",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000025",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000026",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000027",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000028",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000029",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c0000000000002a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c0000000000002b",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c0000000000002c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c0000000000002d",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c0000000000002e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c0000000000002f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000030",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000031",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000032",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000033",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000034",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000035",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000036",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000037",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000038",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000039",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c0000000000003a",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c0000000000003b",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c0000000000003c",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c0000000000003d",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c0000000000003e",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c0000000000003f",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000040",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000041",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000042",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000043",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000044",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000045",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000046",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000047",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000048",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000049",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c0000000000004a",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c0000000000004b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c0000000000004c",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c0000000000004d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c0000000000004e",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c0000000000004f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000050",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000051",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000052",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000053",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000054",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000055",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000056",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000057",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000058",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000059",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c0000000000005a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c0000000000005b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c0000000000005c",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c0000000000005d",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c0000000000005e",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c0000000000005f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000060",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000061",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000062",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c00000000000063",
+ "nodes": [9],
+ "failure": "NONE"
+ }
+ ]
+} \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/distbit32.java.results b/vdslib/src/tests/distribution/testdata/distbit32.java.results
new file mode 100644
index 00000000000..513b8025f0f
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/distbit32.java.results
@@ -0,0 +1,510 @@
+{
+ "cluster-state": "bits:32 distributor:10",
+ "distribution": "redundancy 3\ninitial_redundancy 0\nensure_primary_persisted true\nready_copies 0\nactive_per_leaf_group false\ndistributor_auto_ownership_transfer_on_whole_group_down true\ngroup[0].index \"invalid\"\ngroup[0].name \"invalid\"\ngroup[0].capacity 1.0\ngroup[0].partitions \"*\"\ngroup[0].nodes[0].index 0\ngroup[0].nodes[0].retired false\ngroup[0].nodes[1].index 1\ngroup[0].nodes[1].retired false\ngroup[0].nodes[2].index 2\ngroup[0].nodes[2].retired false\ngroup[0].nodes[3].index 3\ngroup[0].nodes[3].retired false\ngroup[0].nodes[4].index 4\ngroup[0].nodes[4].retired false\ngroup[0].nodes[5].index 5\ngroup[0].nodes[5].retired false\ngroup[0].nodes[6].index 6\ngroup[0].nodes[6].retired false\ngroup[0].nodes[7].index 7\ngroup[0].nodes[7].retired false\ngroup[0].nodes[8].index 8\ngroup[0].nodes[8].retired false\ngroup[0].nodes[9].index 9\ngroup[0].nodes[9].retired false\ndisk_distribution MODULO_BID",
+ "node-type": "distributor",
+ "redundancy": 3,
+ "node-count": 10,
+ "up-states": "uim",
+ "result": [
+ {
+ "bucket": "8000000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000008",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000009",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000000a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000000b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000000c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000000d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000000e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000010",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000011",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000012",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000014",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000015",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000016",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000017",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000018",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000019",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000001a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000001b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000001c",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000001d",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000001e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000001f",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000020",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000021",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000022",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000023",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000024",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000025",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000026",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000027",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000028",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000029",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000002a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000002b",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000002c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000002d",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000002e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000002f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000030",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000031",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000032",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000033",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000034",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000035",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000036",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000037",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000038",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000039",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000003a",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000003b",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000003c",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000003d",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000003e",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000003f",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000040",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000041",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000042",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000043",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000044",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000045",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000046",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000047",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000048",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000049",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000004a",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000004b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000004c",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000004d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000004e",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000004f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000050",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000051",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000052",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000053",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000054",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000055",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000056",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000057",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000058",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000059",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000005a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000005b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000005c",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000005d",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000005e",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "800000000000005f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000060",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000061",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000062",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8000000000000063",
+ "nodes": [9],
+ "failure": "NONE"
+ }
+ ]
+} \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/distbit4.java.results b/vdslib/src/tests/distribution/testdata/distbit4.java.results
new file mode 100644
index 00000000000..66edc3cc5f9
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/distbit4.java.results
@@ -0,0 +1,510 @@
+{
+ "cluster-state": "bits:4 distributor:10",
+ "distribution": "redundancy 3\ninitial_redundancy 0\nensure_primary_persisted true\nready_copies 0\nactive_per_leaf_group false\ndistributor_auto_ownership_transfer_on_whole_group_down true\ngroup[0].index \"invalid\"\ngroup[0].name \"invalid\"\ngroup[0].capacity 1.0\ngroup[0].partitions \"*\"\ngroup[0].nodes[0].index 0\ngroup[0].nodes[0].retired false\ngroup[0].nodes[1].index 1\ngroup[0].nodes[1].retired false\ngroup[0].nodes[2].index 2\ngroup[0].nodes[2].retired false\ngroup[0].nodes[3].index 3\ngroup[0].nodes[3].retired false\ngroup[0].nodes[4].index 4\ngroup[0].nodes[4].retired false\ngroup[0].nodes[5].index 5\ngroup[0].nodes[5].retired false\ngroup[0].nodes[6].index 6\ngroup[0].nodes[6].retired false\ngroup[0].nodes[7].index 7\ngroup[0].nodes[7].retired false\ngroup[0].nodes[8].index 8\ngroup[0].nodes[8].retired false\ngroup[0].nodes[9].index 9\ngroup[0].nodes[9].retired false\ndisk_distribution MODULO_BID",
+ "node-type": "distributor",
+ "redundancy": 3,
+ "node-count": 10,
+ "up-states": "uim",
+ "result": [
+ {
+ "bucket": "1000000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000008",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000009",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "100000000000000a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "100000000000000b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "100000000000000c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "100000000000000d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "100000000000000e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "100000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000008",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000009",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "100000000000000a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "100000000000000b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "100000000000000c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "100000000000000d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "100000000000000e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "100000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000008",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000009",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "100000000000000a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "100000000000000b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "100000000000000c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "100000000000000d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "100000000000000e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "100000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000008",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000009",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "100000000000000a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "100000000000000b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "100000000000000c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "100000000000000d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "100000000000000e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "100000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000008",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000009",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "100000000000000a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "100000000000000b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "100000000000000c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "100000000000000d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "100000000000000e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "100000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000008",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000009",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "100000000000000a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "100000000000000b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "100000000000000c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "100000000000000d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "100000000000000e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "100000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1000000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ }
+ ]
+} \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/distbit5.java.results b/vdslib/src/tests/distribution/testdata/distbit5.java.results
new file mode 100644
index 00000000000..bbdec730140
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/distbit5.java.results
@@ -0,0 +1,510 @@
+{
+ "cluster-state": "bits:5 distributor:10",
+ "distribution": "redundancy 3\ninitial_redundancy 0\nensure_primary_persisted true\nready_copies 0\nactive_per_leaf_group false\ndistributor_auto_ownership_transfer_on_whole_group_down true\ngroup[0].index \"invalid\"\ngroup[0].name \"invalid\"\ngroup[0].capacity 1.0\ngroup[0].partitions \"*\"\ngroup[0].nodes[0].index 0\ngroup[0].nodes[0].retired false\ngroup[0].nodes[1].index 1\ngroup[0].nodes[1].retired false\ngroup[0].nodes[2].index 2\ngroup[0].nodes[2].retired false\ngroup[0].nodes[3].index 3\ngroup[0].nodes[3].retired false\ngroup[0].nodes[4].index 4\ngroup[0].nodes[4].retired false\ngroup[0].nodes[5].index 5\ngroup[0].nodes[5].retired false\ngroup[0].nodes[6].index 6\ngroup[0].nodes[6].retired false\ngroup[0].nodes[7].index 7\ngroup[0].nodes[7].retired false\ngroup[0].nodes[8].index 8\ngroup[0].nodes[8].retired false\ngroup[0].nodes[9].index 9\ngroup[0].nodes[9].retired false\ndisk_distribution MODULO_BID",
+ "node-type": "distributor",
+ "redundancy": 3,
+ "node-count": 10,
+ "up-states": "uim",
+ "result": [
+ {
+ "bucket": "1400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000008",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000009",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "140000000000000a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "140000000000000b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "140000000000000c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "140000000000000d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "140000000000000e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "140000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000010",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000011",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000012",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000014",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000015",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000016",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000017",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000018",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000019",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "140000000000001a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "140000000000001b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "140000000000001c",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "140000000000001d",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "140000000000001e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "140000000000001f",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000008",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000009",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "140000000000000a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "140000000000000b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "140000000000000c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "140000000000000d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "140000000000000e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "140000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000010",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000011",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000012",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000014",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000015",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000016",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000017",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000018",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000019",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "140000000000001a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "140000000000001b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "140000000000001c",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "140000000000001d",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "140000000000001e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "140000000000001f",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000008",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000009",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "140000000000000a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "140000000000000b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "140000000000000c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "140000000000000d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "140000000000000e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "140000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000010",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000011",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000012",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000014",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000015",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000016",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000017",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000018",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000019",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "140000000000001a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "140000000000001b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "140000000000001c",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "140000000000001d",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "140000000000001e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "140000000000001f",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1400000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ }
+ ]
+} \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/distbit6.java.results b/vdslib/src/tests/distribution/testdata/distbit6.java.results
new file mode 100644
index 00000000000..f67ed3741d2
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/distbit6.java.results
@@ -0,0 +1,510 @@
+{
+ "cluster-state": "bits:6 distributor:10",
+ "distribution": "redundancy 3\ninitial_redundancy 0\nensure_primary_persisted true\nready_copies 0\nactive_per_leaf_group false\ndistributor_auto_ownership_transfer_on_whole_group_down true\ngroup[0].index \"invalid\"\ngroup[0].name \"invalid\"\ngroup[0].capacity 1.0\ngroup[0].partitions \"*\"\ngroup[0].nodes[0].index 0\ngroup[0].nodes[0].retired false\ngroup[0].nodes[1].index 1\ngroup[0].nodes[1].retired false\ngroup[0].nodes[2].index 2\ngroup[0].nodes[2].retired false\ngroup[0].nodes[3].index 3\ngroup[0].nodes[3].retired false\ngroup[0].nodes[4].index 4\ngroup[0].nodes[4].retired false\ngroup[0].nodes[5].index 5\ngroup[0].nodes[5].retired false\ngroup[0].nodes[6].index 6\ngroup[0].nodes[6].retired false\ngroup[0].nodes[7].index 7\ngroup[0].nodes[7].retired false\ngroup[0].nodes[8].index 8\ngroup[0].nodes[8].retired false\ngroup[0].nodes[9].index 9\ngroup[0].nodes[9].retired false\ndisk_distribution MODULO_BID",
+ "node-type": "distributor",
+ "redundancy": 3,
+ "node-count": 10,
+ "up-states": "uim",
+ "result": [
+ {
+ "bucket": "1800000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000008",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000009",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "180000000000000a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "180000000000000b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "180000000000000c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "180000000000000d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "180000000000000e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "180000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000010",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000011",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000012",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000014",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000015",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000016",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000017",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000018",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000019",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "180000000000001a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "180000000000001b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "180000000000001c",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "180000000000001d",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "180000000000001e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "180000000000001f",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000020",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000021",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000022",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000023",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000024",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000025",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000026",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000027",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000028",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000029",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "180000000000002a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "180000000000002b",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "180000000000002c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "180000000000002d",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "180000000000002e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "180000000000002f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000030",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000031",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000032",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000033",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000034",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000035",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000036",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000037",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000038",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000039",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "180000000000003a",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "180000000000003b",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "180000000000003c",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "180000000000003d",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "180000000000003e",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "180000000000003f",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000008",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000009",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "180000000000000a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "180000000000000b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "180000000000000c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "180000000000000d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "180000000000000e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "180000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000010",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000011",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000012",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000014",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000015",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000016",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000017",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000018",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000019",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "180000000000001a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "180000000000001b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "180000000000001c",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "180000000000001d",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "180000000000001e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "180000000000001f",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000020",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000021",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000022",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1800000000000023",
+ "nodes": [7],
+ "failure": "NONE"
+ }
+ ]
+} \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/distbit7.java.results b/vdslib/src/tests/distribution/testdata/distbit7.java.results
new file mode 100644
index 00000000000..4c06e5b2c53
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/distbit7.java.results
@@ -0,0 +1,510 @@
+{
+ "cluster-state": "bits:7 distributor:10",
+ "distribution": "redundancy 3\ninitial_redundancy 0\nensure_primary_persisted true\nready_copies 0\nactive_per_leaf_group false\ndistributor_auto_ownership_transfer_on_whole_group_down true\ngroup[0].index \"invalid\"\ngroup[0].name \"invalid\"\ngroup[0].capacity 1.0\ngroup[0].partitions \"*\"\ngroup[0].nodes[0].index 0\ngroup[0].nodes[0].retired false\ngroup[0].nodes[1].index 1\ngroup[0].nodes[1].retired false\ngroup[0].nodes[2].index 2\ngroup[0].nodes[2].retired false\ngroup[0].nodes[3].index 3\ngroup[0].nodes[3].retired false\ngroup[0].nodes[4].index 4\ngroup[0].nodes[4].retired false\ngroup[0].nodes[5].index 5\ngroup[0].nodes[5].retired false\ngroup[0].nodes[6].index 6\ngroup[0].nodes[6].retired false\ngroup[0].nodes[7].index 7\ngroup[0].nodes[7].retired false\ngroup[0].nodes[8].index 8\ngroup[0].nodes[8].retired false\ngroup[0].nodes[9].index 9\ngroup[0].nodes[9].retired false\ndisk_distribution MODULO_BID",
+ "node-type": "distributor",
+ "redundancy": 3,
+ "node-count": 10,
+ "up-states": "uim",
+ "result": [
+ {
+ "bucket": "1c00000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000008",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000009",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c0000000000000a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c0000000000000b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c0000000000000c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c0000000000000d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c0000000000000e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c0000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000010",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000011",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000012",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000014",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000015",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000016",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000017",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000018",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000019",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c0000000000001a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c0000000000001b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c0000000000001c",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c0000000000001d",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c0000000000001e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c0000000000001f",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000020",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000021",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000022",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000023",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000024",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000025",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000026",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000027",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000028",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000029",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c0000000000002a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c0000000000002b",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c0000000000002c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c0000000000002d",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c0000000000002e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c0000000000002f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000030",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000031",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000032",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000033",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000034",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000035",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000036",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000037",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000038",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000039",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c0000000000003a",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c0000000000003b",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c0000000000003c",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c0000000000003d",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c0000000000003e",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c0000000000003f",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000040",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000041",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000042",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000043",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000044",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000045",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000046",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000047",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000048",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000049",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c0000000000004a",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c0000000000004b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c0000000000004c",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c0000000000004d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c0000000000004e",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c0000000000004f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000050",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000051",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000052",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000053",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000054",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000055",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000056",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000057",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000058",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000059",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c0000000000005a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c0000000000005b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c0000000000005c",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c0000000000005d",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c0000000000005e",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c0000000000005f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000060",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000061",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000062",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "1c00000000000063",
+ "nodes": [9],
+ "failure": "NONE"
+ }
+ ]
+} \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/distbit8.java.results b/vdslib/src/tests/distribution/testdata/distbit8.java.results
new file mode 100644
index 00000000000..0fbdc75d737
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/distbit8.java.results
@@ -0,0 +1,510 @@
+{
+ "cluster-state": "bits:8 distributor:10",
+ "distribution": "redundancy 3\ninitial_redundancy 0\nensure_primary_persisted true\nready_copies 0\nactive_per_leaf_group false\ndistributor_auto_ownership_transfer_on_whole_group_down true\ngroup[0].index \"invalid\"\ngroup[0].name \"invalid\"\ngroup[0].capacity 1.0\ngroup[0].partitions \"*\"\ngroup[0].nodes[0].index 0\ngroup[0].nodes[0].retired false\ngroup[0].nodes[1].index 1\ngroup[0].nodes[1].retired false\ngroup[0].nodes[2].index 2\ngroup[0].nodes[2].retired false\ngroup[0].nodes[3].index 3\ngroup[0].nodes[3].retired false\ngroup[0].nodes[4].index 4\ngroup[0].nodes[4].retired false\ngroup[0].nodes[5].index 5\ngroup[0].nodes[5].retired false\ngroup[0].nodes[6].index 6\ngroup[0].nodes[6].retired false\ngroup[0].nodes[7].index 7\ngroup[0].nodes[7].retired false\ngroup[0].nodes[8].index 8\ngroup[0].nodes[8].retired false\ngroup[0].nodes[9].index 9\ngroup[0].nodes[9].retired false\ndisk_distribution MODULO_BID",
+ "node-type": "distributor",
+ "redundancy": 3,
+ "node-count": 10,
+ "up-states": "uim",
+ "result": [
+ {
+ "bucket": "2000000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000008",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000009",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "200000000000000a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "200000000000000b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "200000000000000c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "200000000000000d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "200000000000000e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "200000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000010",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000011",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000012",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000014",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000015",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000016",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000017",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000018",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000019",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "200000000000001a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "200000000000001b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "200000000000001c",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "200000000000001d",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "200000000000001e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "200000000000001f",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000020",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000021",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000022",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000023",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000024",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000025",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000026",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000027",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000028",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000029",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "200000000000002a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "200000000000002b",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "200000000000002c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "200000000000002d",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "200000000000002e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "200000000000002f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000030",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000031",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000032",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000033",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000034",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000035",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000036",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000037",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000038",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000039",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "200000000000003a",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "200000000000003b",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "200000000000003c",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "200000000000003d",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "200000000000003e",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "200000000000003f",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000040",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000041",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000042",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000043",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000044",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000045",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000046",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000047",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000048",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000049",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "200000000000004a",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "200000000000004b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "200000000000004c",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "200000000000004d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "200000000000004e",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "200000000000004f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000050",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000051",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000052",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000053",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000054",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000055",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000056",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000057",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000058",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000059",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "200000000000005a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "200000000000005b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "200000000000005c",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "200000000000005d",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "200000000000005e",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "200000000000005f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000060",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000061",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000062",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2000000000000063",
+ "nodes": [9],
+ "failure": "NONE"
+ }
+ ]
+} \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/distbit9.java.results b/vdslib/src/tests/distribution/testdata/distbit9.java.results
new file mode 100644
index 00000000000..165507ef558
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/distbit9.java.results
@@ -0,0 +1,510 @@
+{
+ "cluster-state": "bits:9 distributor:10",
+ "distribution": "redundancy 3\ninitial_redundancy 0\nensure_primary_persisted true\nready_copies 0\nactive_per_leaf_group false\ndistributor_auto_ownership_transfer_on_whole_group_down true\ngroup[0].index \"invalid\"\ngroup[0].name \"invalid\"\ngroup[0].capacity 1.0\ngroup[0].partitions \"*\"\ngroup[0].nodes[0].index 0\ngroup[0].nodes[0].retired false\ngroup[0].nodes[1].index 1\ngroup[0].nodes[1].retired false\ngroup[0].nodes[2].index 2\ngroup[0].nodes[2].retired false\ngroup[0].nodes[3].index 3\ngroup[0].nodes[3].retired false\ngroup[0].nodes[4].index 4\ngroup[0].nodes[4].retired false\ngroup[0].nodes[5].index 5\ngroup[0].nodes[5].retired false\ngroup[0].nodes[6].index 6\ngroup[0].nodes[6].retired false\ngroup[0].nodes[7].index 7\ngroup[0].nodes[7].retired false\ngroup[0].nodes[8].index 8\ngroup[0].nodes[8].retired false\ngroup[0].nodes[9].index 9\ngroup[0].nodes[9].retired false\ndisk_distribution MODULO_BID",
+ "node-type": "distributor",
+ "redundancy": 3,
+ "node-count": 10,
+ "up-states": "uim",
+ "result": [
+ {
+ "bucket": "2400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000008",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000009",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "240000000000000a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "240000000000000b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "240000000000000c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "240000000000000d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "240000000000000e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "240000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000010",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000011",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000012",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000014",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000015",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000016",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000017",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000018",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000019",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "240000000000001a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "240000000000001b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "240000000000001c",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "240000000000001d",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "240000000000001e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "240000000000001f",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000020",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000021",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000022",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000023",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000024",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000025",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000026",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000027",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000028",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000029",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "240000000000002a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "240000000000002b",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "240000000000002c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "240000000000002d",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "240000000000002e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "240000000000002f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000030",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000031",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000032",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000033",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000034",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000035",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000036",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000037",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000038",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000039",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "240000000000003a",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "240000000000003b",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "240000000000003c",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "240000000000003d",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "240000000000003e",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "240000000000003f",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000040",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000041",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000042",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000043",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000044",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000045",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000046",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000047",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000048",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000049",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "240000000000004a",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "240000000000004b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "240000000000004c",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "240000000000004d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "240000000000004e",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "240000000000004f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000050",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000051",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000052",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000053",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000054",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000055",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000056",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000057",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000058",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000059",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "240000000000005a",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "240000000000005b",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "240000000000005c",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "240000000000005d",
+ "nodes": [9],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "240000000000005e",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "240000000000005f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000060",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000061",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000062",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "2400000000000063",
+ "nodes": [9],
+ "failure": "NONE"
+ }
+ ]
+} \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/down.java.results b/vdslib/src/tests/distribution/testdata/down.java.results
new file mode 100644
index 00000000000..5189d2d4c0c
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/down.java.results
@@ -0,0 +1,730 @@
+{
+ "cluster-state": "distributor:10 .4.s:m .5.s:m .6.s:d .7.s:d .8.s:r .9.s:r",
+ "distribution": "redundancy 3\ninitial_redundancy 0\nensure_primary_persisted true\nready_copies 0\nactive_per_leaf_group false\ndistributor_auto_ownership_transfer_on_whole_group_down true\ngroup[0].index \"invalid\"\ngroup[0].name \"invalid\"\ngroup[0].capacity 1.0\ngroup[0].partitions \"*\"\ngroup[0].nodes[0].index 0\ngroup[0].nodes[0].retired false\ngroup[0].nodes[1].index 1\ngroup[0].nodes[1].retired false\ngroup[0].nodes[2].index 2\ngroup[0].nodes[2].retired false\ngroup[0].nodes[3].index 3\ngroup[0].nodes[3].retired false\ngroup[0].nodes[4].index 4\ngroup[0].nodes[4].retired false\ngroup[0].nodes[5].index 5\ngroup[0].nodes[5].retired false\ngroup[0].nodes[6].index 6\ngroup[0].nodes[6].retired false\ngroup[0].nodes[7].index 7\ngroup[0].nodes[7].retired false\ngroup[0].nodes[8].index 8\ngroup[0].nodes[8].retired false\ngroup[0].nodes[9].index 9\ngroup[0].nodes[9].retired false\ndisk_distribution MODULO_BID",
+ "node-type": "distributor",
+ "redundancy": 3,
+ "node-count": 10,
+ "up-states": "u",
+ "result": [
+ {
+ "bucket": "4000000000000000",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000002",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000003",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000004",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000005",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000006",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000007",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000008",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000009",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000a",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000b",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000d",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000010",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000011",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000012",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000000",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000002",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000003",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000004",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000005",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000006",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000007",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000008",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000009",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000000a",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000000b",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000000c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000000d",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000000e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000010",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000011",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000012",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000000",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000002",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000003",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000004",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000005",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000006",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000007",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000008",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000009",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000000a",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000000b",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000000c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000000d",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000000e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000010",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000011",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000012",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000001fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000001fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c0000000001fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "500000000009fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "540000000009fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "580000000009fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c0000000049fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "600000000049fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "640000000149fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "680000000349fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c0000000749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "700000000749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "740000001749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "780000003749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c0000003749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "80000000b749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "84000001b749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "88000003b749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8c000007b749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "9000000fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "9400001fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "9800003fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "9c00007fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "a000007fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "a400007fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "a800007fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "ac00047fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "b000047fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "b400147fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "b800347fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "bc00347fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c000b47fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c400b47fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c800b47fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "cc00b47fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "d000b47fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "d400b47fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "d800b47fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "dc00b47fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "e000b47fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "e400b47fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000098d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "44000000000098d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "48000000000298d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c000000000698d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "50000000000e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "54000000000e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "58000000002e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c000000002e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "60000000002e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "64000000012e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "68000000012e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c000000052e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "70000000052e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "74000000152e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "78000000152e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c000000152e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "80000000952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "84000001952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "88000001952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8c000001952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "90000001952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "94000001952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "98000001952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "9c000041952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "a00000c1952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "a40000c1952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "a80002c1952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "ac0002c1952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "b00002c1952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "b40012c1952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "b80012c1952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "bc0012c1952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00092c1952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c40192c1952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c80192c1952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "cc0192c1952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "d00992c1952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "d41992c1952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "d83992c1952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "dc7992c1952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "e07992c1952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "e47992c1952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ }
+ ]
+} \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/group-capacity.java.results b/vdslib/src/tests/distribution/testdata/group-capacity.java.results
new file mode 100644
index 00000000000..99b6d7321ce
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/group-capacity.java.results
@@ -0,0 +1,4510 @@
+{
+ "cluster-state": "distributor:9",
+ "distribution": "redundancy 6\ninitial_redundancy 0\nensure_primary_persisted true\nready_copies 0\nactive_per_leaf_group false\ndistributor_auto_ownership_transfer_on_whole_group_down true\ngroup[0].index \"invalid\"\ngroup[0].name \"invalid\"\ngroup[0].capacity 1.0\ngroup[0].partitions \"1|*\"\ngroup[1].index \"0\"\ngroup[1].name \"top.0\"\ngroup[1].capacity 3.0\ngroup[1].partitions \"\"\ngroup[1].nodes[0].index 8\ngroup[1].nodes[0].retired false\ngroup[1].nodes[1].index 1\ngroup[1].nodes[1].retired false\ngroup[1].nodes[2].index 6\ngroup[1].nodes[2].retired false\ngroup[2].index \"1\"\ngroup[2].name \"top.1\"\ngroup[2].capacity 1.0\ngroup[2].partitions \"\"\ngroup[2].nodes[0].index 5\ngroup[2].nodes[0].retired false\ngroup[2].nodes[1].index 0\ngroup[2].nodes[1].retired false\ngroup[2].nodes[2].index 2\ngroup[2].nodes[2].retired false\ngroup[3].index \"2\"\ngroup[3].name \"top.2\"\ngroup[3].capacity 1.0\ngroup[3].partitions \"\"\ngroup[3].nodes[0].index 4\ngroup[3].nodes[0].retired false\ngroup[3].nodes[1].index 3\ngroup[3].nodes[1].retired false\ngroup[3].nodes[2].index 7\ngroup[3].nodes[2].retired false\ndisk_distribution MODULO_BID",
+ "node-type": "distributor",
+ "redundancy": 3,
+ "node-count": 9,
+ "up-states": "uim",
+ "result": [
+ {
+ "bucket": "4000000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000001",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000002",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000003",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000004",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000008",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000009",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000b",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000c",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000d",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000010",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000011",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000012",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000014",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000015",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000016",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000017",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000018",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000019",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001b",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001c",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001d",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000001f",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000020",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000021",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000022",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000023",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000024",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000025",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000026",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000027",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000028",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000029",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000002a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000002b",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000002c",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000002d",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000002e",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000002f",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000030",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000031",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000032",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000033",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000034",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000035",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000036",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000037",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000038",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000039",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000003a",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000003b",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000003c",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000003d",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000003e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000003f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000040",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000041",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000042",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000043",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000044",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000045",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000046",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000047",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000048",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000049",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000004a",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000004b",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000004c",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000004d",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000004e",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000004f",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000050",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000051",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000052",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000053",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000054",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000055",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000056",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000057",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000058",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000059",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000005a",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000005b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000005c",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000005d",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000005e",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000005f",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000060",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000061",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000062",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000063",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000064",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000065",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000066",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000067",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000068",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000069",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000006a",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000006b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000006c",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000006d",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000006e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000006f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000070",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000071",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000072",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000073",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000074",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000075",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000076",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000077",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000078",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000079",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000007a",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000007b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000007c",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000007d",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000007e",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000007f",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000080",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000081",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000082",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000083",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000084",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000085",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000086",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000087",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000088",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000089",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000008a",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000008b",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000008c",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000008d",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000008e",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000008f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000090",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000091",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000092",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000093",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000094",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000095",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000096",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000097",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000098",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000099",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000009a",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000009b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000009c",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000009d",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000009e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000009f",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000a0",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000a1",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000a2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000a3",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000a4",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000a5",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000a6",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000a7",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000a8",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000a9",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000aa",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000ab",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000ac",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000ad",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000ae",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000af",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000b0",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000b1",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000b2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000b3",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000b4",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000b5",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000b6",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000b7",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000b8",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000b9",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000ba",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000bb",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000bc",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000bd",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000be",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000bf",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000c0",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000c1",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000c2",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000c3",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000c4",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000c5",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000c6",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000c7",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000c8",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000c9",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000ca",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000cb",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000cc",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000cd",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000ce",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000cf",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000d0",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000d1",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000d2",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000d3",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000d4",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000d5",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000d6",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000d7",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000d8",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000d9",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000da",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000db",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000dc",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000dd",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000de",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000df",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000e0",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000e1",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000e2",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000e3",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000e4",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000e5",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000e6",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000e7",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000e8",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000e9",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000ea",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000eb",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000ec",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000ed",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000ee",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000ef",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000f0",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000f1",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000f2",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000f3",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000f4",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000f5",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000f6",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000f7",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000f8",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000f9",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000fa",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000fb",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000fc",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000fd",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000fe",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000000ff",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000100",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000101",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000102",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000103",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000104",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000105",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000106",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000107",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000108",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000109",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000010a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000010b",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000010c",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000010d",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000010e",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000010f",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000110",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000111",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000112",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000113",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000114",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000115",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000116",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000117",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000118",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000119",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000011a",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000011b",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000011c",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000011d",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000011e",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000011f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000120",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000121",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000122",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000123",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000124",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000125",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000126",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000127",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000128",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000129",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000012a",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000012b",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000012c",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000012d",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000012e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000012f",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000130",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000131",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000132",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000133",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000134",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000135",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000136",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000137",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000138",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000139",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000013a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000013b",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000013c",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000013d",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000013e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000013f",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000140",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000141",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000142",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000143",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000144",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000145",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000146",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000147",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000148",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000149",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000014a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000014b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000014c",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000014d",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000014e",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000014f",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000150",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000151",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000152",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000153",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000154",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000155",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000156",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000157",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000158",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000159",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000015a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000015b",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000015c",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000015d",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000015e",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000015f",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000160",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000161",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000162",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000163",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000164",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000165",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000166",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000167",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000168",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000169",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000016a",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000016b",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000016c",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000016d",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000016e",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000016f",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000170",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000171",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000172",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000173",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000174",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000175",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000176",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000177",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000178",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000179",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000017a",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000017b",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000017c",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000017d",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000017e",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000017f",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000180",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000181",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000182",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000183",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000184",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000185",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000186",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000187",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000188",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000189",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000018a",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000018b",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000018c",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000018d",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000018e",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000018f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000190",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000191",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000192",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000193",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000194",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000195",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000196",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000197",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000198",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000199",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000019a",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000019b",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000019c",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000019d",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000019e",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000019f",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001a0",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001a1",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001a2",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001a3",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001a4",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001a5",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001a6",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001a7",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001a8",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001a9",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001aa",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001ab",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001ac",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001ad",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001ae",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001af",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001b0",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001b1",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001b2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001b3",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001b4",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001b5",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001b6",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001b7",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001b8",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001b9",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001ba",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001bb",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001bc",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001bd",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001be",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001bf",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001c0",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001c1",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001c2",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001c3",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001c4",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001c5",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001c6",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001c7",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001c8",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001c9",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001ca",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001cb",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001cc",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001cd",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001ce",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001cf",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001d0",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001d1",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001d3",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001d4",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001d5",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001d6",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001d7",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001d8",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001d9",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001da",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001db",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001dc",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001dd",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001de",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001df",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001e0",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001e1",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001e2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001e3",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001e4",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001e5",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001e6",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001e7",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001e8",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001e9",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001ea",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001eb",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001ec",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001ed",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001ee",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001ef",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001f0",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001f1",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001f2",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001f3",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001f4",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001f5",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001f6",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001f7",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001f8",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001f9",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001fa",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001fb",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001fc",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001fd",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001fe",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000001ff",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000200",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000201",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000202",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000203",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000204",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000205",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000206",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000207",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000208",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000209",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000020a",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000020b",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000020c",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000020d",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000020e",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000020f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000210",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000211",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000212",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000213",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000214",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000215",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000216",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000217",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000218",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000219",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000021a",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000021b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000021c",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000021d",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000021e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000021f",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000220",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000221",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000222",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000223",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000224",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000225",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000226",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000227",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000228",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000229",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000022a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000022b",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000022c",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000022d",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000022e",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000022f",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000230",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000231",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000232",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000233",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000234",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000235",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000236",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000237",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000238",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000239",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000023a",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000023b",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000023c",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000023d",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000023e",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000023f",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000240",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000241",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000242",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000243",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000244",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000245",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000246",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000247",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000248",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000249",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000024a",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000024b",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000024c",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000024d",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000024e",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000024f",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000250",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000251",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000252",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000253",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000254",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000255",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000256",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000257",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000258",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000259",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000025a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000025b",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000025c",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000025d",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000025e",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000025f",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000260",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000261",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000262",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000263",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000264",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000265",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000266",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000267",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000268",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000269",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000026a",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000026b",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000026c",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000026d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000026e",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000026f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000270",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000271",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000272",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000273",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000274",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000275",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000276",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000277",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000278",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000279",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000027a",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000027b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000027c",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000027d",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000027e",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000027f",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000280",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000281",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000282",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000283",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000284",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000285",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000286",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000287",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000288",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000289",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000028a",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000028b",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000028c",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000028d",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000028e",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000028f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000290",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000291",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000292",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000293",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000294",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000295",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000296",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000297",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000298",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000299",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000029a",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000029b",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000029c",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000029d",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000029e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000029f",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002a0",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002a1",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002a2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002a3",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002a4",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002a5",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002a6",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002a7",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002a8",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002a9",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002aa",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002ab",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002ac",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002ad",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002ae",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002af",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002b0",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002b1",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002b2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002b3",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002b4",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002b5",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002b6",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002b7",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002b8",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002b9",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002ba",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002bb",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002bc",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002bd",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002be",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002bf",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002c0",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002c1",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002c2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002c3",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002c4",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002c5",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002c6",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002c7",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002c8",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002c9",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002ca",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002cb",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002cc",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002cd",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002ce",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002cf",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002d0",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002d1",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002d2",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002d3",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002d4",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002d5",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002d6",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002d7",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002d8",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002d9",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002da",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002db",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002dc",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002dd",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002de",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002df",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002e0",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002e1",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002e2",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002e3",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002e4",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002e5",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002e6",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002e7",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002e8",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002e9",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002ea",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002eb",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002ec",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002ed",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002ee",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002ef",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002f0",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002f1",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002f2",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002f3",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002f4",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002f5",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002f6",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002f7",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002f8",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002f9",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002fa",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002fb",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002fc",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002fd",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002fe",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000002ff",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000300",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000301",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000302",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000303",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000304",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000305",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000306",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000307",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000308",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000309",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000030a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000030b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000030c",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000030d",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000030e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000030f",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000310",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000311",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000312",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000313",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000314",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000315",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000316",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000317",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000318",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000319",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000031a",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000031b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000031c",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000031d",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000031e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000031f",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000320",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000321",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000322",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000323",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000324",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000325",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000326",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000327",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000328",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000329",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000032a",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000032b",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000032c",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000032d",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000032e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000032f",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000330",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000331",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000332",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000333",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000334",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000335",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000336",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000337",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000338",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000339",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000033a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000033b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000033c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000033d",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000033e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000033f",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000340",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000341",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000342",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000343",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000344",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000345",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000346",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000347",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000348",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000349",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000034a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000034b",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000034c",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000034d",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000034e",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000034f",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000350",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000351",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000352",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000353",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000354",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000355",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000356",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000357",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000358",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000359",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000035a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000035b",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000035c",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000035d",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000035e",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000035f",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000360",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000361",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000362",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000363",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000364",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000365",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000366",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000367",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000368",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000369",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000036a",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000036b",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000036c",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000036d",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000036e",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000036f",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000370",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000371",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000372",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000373",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000374",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000375",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000376",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000377",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000378",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000379",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000037a",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000037b",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000037c",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000037d",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000037e",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000037f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000380",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000381",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000382",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000383",
+ "nodes": [8],
+ "failure": "NONE"
+ }
+ ]
+} \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/hierarchical-grouping-deep.java.results b/vdslib/src/tests/distribution/testdata/hierarchical-grouping-deep.java.results
new file mode 100644
index 00000000000..21ccd89d28b
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/hierarchical-grouping-deep.java.results
@@ -0,0 +1,730 @@
+{
+ "cluster-state": "distributor:500",
+ "distribution": "redundancy 8\ninitial_redundancy 0\nensure_primary_persisted true\nready_copies 0\nactive_per_leaf_group false\ndistributor_auto_ownership_transfer_on_whole_group_down true\ngroup[0].index \"invalid\"\ngroup[0].name \"invalid\"\ngroup[0].capacity 1.0\ngroup[0].partitions \"*|*\"\ngroup[1].index \"0\"\ngroup[1].name \"top.0\"\ngroup[1].capacity 1.0\ngroup[1].partitions \"*|*\"\ngroup[2].index \"0.0\"\ngroup[2].name \"top.0.0\"\ngroup[2].capacity 1.0\ngroup[2].partitions \"*|*\"\ngroup[3].index \"0.0.0\"\ngroup[3].name \"top.0.0.0\"\ngroup[3].capacity 1.0\ngroup[3].partitions \"\"\ngroup[3].nodes[0].index 32\ngroup[3].nodes[0].retired false\ngroup[3].nodes[1].index 64\ngroup[3].nodes[1].retired false\ngroup[3].nodes[2].index 286\ngroup[3].nodes[2].retired false\ngroup[4].index \"0.0.1\"\ngroup[4].name \"top.0.0.1\"\ngroup[4].capacity 1.0\ngroup[4].partitions \"\"\ngroup[4].nodes[0].index 317\ngroup[4].nodes[0].retired false\ngroup[4].nodes[1].index 374\ngroup[4].nodes[1].retired false\ngroup[4].nodes[2].index 47\ngroup[4].nodes[2].retired false\ngroup[5].index \"0.0.2\"\ngroup[5].name \"top.0.0.2\"\ngroup[5].capacity 1.0\ngroup[5].partitions \"\"\ngroup[5].nodes[0].index 63\ngroup[5].nodes[0].retired false\ngroup[5].nodes[1].index 349\ngroup[5].nodes[1].retired false\ngroup[5].nodes[2].index 149\ngroup[5].nodes[2].retired false\ngroup[6].index \"0.0.3\"\ngroup[6].name \"top.0.0.3\"\ngroup[6].capacity 1.0\ngroup[6].partitions \"\"\ngroup[6].nodes[0].index 31\ngroup[6].nodes[0].retired false\ngroup[6].nodes[1].index 314\ngroup[6].nodes[1].retired false\ngroup[6].nodes[2].index 22\ngroup[6].nodes[2].retired false\ngroup[7].index \"0.0.4\"\ngroup[7].name \"top.0.0.4\"\ngroup[7].capacity 1.0\ngroup[7].partitions \"\"\ngroup[7].nodes[0].index 350\ngroup[7].nodes[0].retired false\ngroup[7].nodes[1].index 69\ngroup[7].nodes[1].retired false\ngroup[7].nodes[2].index 144\ngroup[7].nodes[2].retired false\ngroup[8].index \"0.1\"\ngroup[8].name \"top.0.1\"\ngroup[8].capacity 1.0\ngroup[8].partitions \"*|*\"\ngroup[9].index \"0.1.0\"\ngroup[9].name \"top.0.1.0\"\ngroup[9].capacity 1.0\ngroup[9].partitions \"\"\ngroup[9].nodes[0].index 189\ngroup[9].nodes[0].retired false\ngroup[9].nodes[1].index 212\ngroup[9].nodes[1].retired false\ngroup[9].nodes[2].index 55\ngroup[9].nodes[2].retired false\ngroup[10].index \"0.1.1\"\ngroup[10].name \"top.0.1.1\"\ngroup[10].capacity 1.0\ngroup[10].partitions \"\"\ngroup[10].nodes[0].index 324\ngroup[10].nodes[0].retired false\ngroup[10].nodes[1].index 236\ngroup[10].nodes[1].retired false\ngroup[10].nodes[2].index 232\ngroup[10].nodes[2].retired false\ngroup[11].index \"0.1.2\"\ngroup[11].name \"top.0.1.2\"\ngroup[11].capacity 1.0\ngroup[11].partitions \"\"\ngroup[11].nodes[0].index 359\ngroup[11].nodes[0].retired false\ngroup[11].nodes[1].index 111\ngroup[11].nodes[1].retired false\ngroup[11].nodes[2].index 170\ngroup[11].nodes[2].retired false\ngroup[12].index \"0.1.3\"\ngroup[12].name \"top.0.1.3\"\ngroup[12].capacity 1.0\ngroup[12].partitions \"\"\ngroup[12].nodes[0].index 251\ngroup[12].nodes[0].retired false\ngroup[12].nodes[1].index 153\ngroup[12].nodes[1].retired false\ngroup[12].nodes[2].index 355\ngroup[12].nodes[2].retired false\ngroup[13].index \"0.1.4\"\ngroup[13].name \"top.0.1.4\"\ngroup[13].capacity 1.0\ngroup[13].partitions \"\"\ngroup[13].nodes[0].index 88\ngroup[13].nodes[0].retired false\ngroup[13].nodes[1].index 99\ngroup[13].nodes[1].retired false\ngroup[13].nodes[2].index 94\ngroup[13].nodes[2].retired false\ngroup[14].index \"0.2\"\ngroup[14].name \"top.0.2\"\ngroup[14].capacity 1.0\ngroup[14].partitions \"*|*\"\ngroup[15].index \"0.2.0\"\ngroup[15].name \"top.0.2.0\"\ngroup[15].capacity 1.0\ngroup[15].partitions \"\"\ngroup[15].nodes[0].index 372\ngroup[15].nodes[0].retired false\ngroup[15].nodes[1].index 228\ngroup[15].nodes[1].retired false\ngroup[15].nodes[2].index 139\ngroup[15].nodes[2].retired false\ngroup[16].index \"0.2.1\"\ngroup[16].name \"top.0.2.1\"\ngroup[16].capacity 1.0\ngroup[16].partitions \"\"\ngroup[16].nodes[0].index 33\ngroup[16].nodes[0].retired false\ngroup[16].nodes[1].index 82\ngroup[16].nodes[1].retired false\ngroup[16].nodes[2].index 255\ngroup[16].nodes[2].retired false\ngroup[17].index \"0.2.2\"\ngroup[17].name \"top.0.2.2\"\ngroup[17].capacity 1.0\ngroup[17].partitions \"\"\ngroup[17].nodes[0].index 337\ngroup[17].nodes[0].retired false\ngroup[17].nodes[1].index 30\ngroup[17].nodes[1].retired false\ngroup[17].nodes[2].index 269\ngroup[17].nodes[2].retired false\ngroup[18].index \"0.2.3\"\ngroup[18].name \"top.0.2.3\"\ngroup[18].capacity 1.0\ngroup[18].partitions \"\"\ngroup[18].nodes[0].index 340\ngroup[18].nodes[0].retired false\ngroup[18].nodes[1].index 243\ngroup[18].nodes[1].retired false\ngroup[18].nodes[2].index 274\ngroup[18].nodes[2].retired false\ngroup[19].index \"0.2.4\"\ngroup[19].name \"top.0.2.4\"\ngroup[19].capacity 1.0\ngroup[19].partitions \"\"\ngroup[19].nodes[0].index 90\ngroup[19].nodes[0].retired false\ngroup[19].nodes[1].index 70\ngroup[19].nodes[1].retired false\ngroup[19].nodes[2].index 160\ngroup[19].nodes[2].retired false\ngroup[20].index \"0.3\"\ngroup[20].name \"top.0.3\"\ngroup[20].capacity 1.0\ngroup[20].partitions \"*|*\"\ngroup[21].index \"0.3.0\"\ngroup[21].name \"top.0.3.0\"\ngroup[21].capacity 1.0\ngroup[21].partitions \"\"\ngroup[21].nodes[0].index 76\ngroup[21].nodes[0].retired false\ngroup[21].nodes[1].index 112\ngroup[21].nodes[1].retired false\ngroup[21].nodes[2].index 74\ngroup[21].nodes[2].retired false\ngroup[22].index \"0.3.1\"\ngroup[22].name \"top.0.3.1\"\ngroup[22].capacity 1.0\ngroup[22].partitions \"\"\ngroup[22].nodes[0].index 43\ngroup[22].nodes[0].retired false\ngroup[22].nodes[1].index 60\ngroup[22].nodes[1].retired false\ngroup[22].nodes[2].index 131\ngroup[22].nodes[2].retired false\ngroup[23].index \"0.3.2\"\ngroup[23].name \"top.0.3.2\"\ngroup[23].capacity 1.0\ngroup[23].partitions \"\"\ngroup[23].nodes[0].index 214\ngroup[23].nodes[0].retired false\ngroup[23].nodes[1].index 321\ngroup[23].nodes[1].retired false\ngroup[23].nodes[2].index 86\ngroup[23].nodes[2].retired false\ngroup[24].index \"0.3.3\"\ngroup[24].name \"top.0.3.3\"\ngroup[24].capacity 1.0\ngroup[24].partitions \"\"\ngroup[24].nodes[0].index 261\ngroup[24].nodes[0].retired false\ngroup[24].nodes[1].index 181\ngroup[24].nodes[1].retired false\ngroup[24].nodes[2].index 48\ngroup[24].nodes[2].retired false\ngroup[25].index \"0.3.4\"\ngroup[25].name \"top.0.3.4\"\ngroup[25].capacity 1.0\ngroup[25].partitions \"\"\ngroup[25].nodes[0].index 56\ngroup[25].nodes[0].retired false\ngroup[25].nodes[1].index 84\ngroup[25].nodes[1].retired false\ngroup[25].nodes[2].index 173\ngroup[25].nodes[2].retired false\ngroup[26].index \"0.4\"\ngroup[26].name \"top.0.4\"\ngroup[26].capacity 1.0\ngroup[26].partitions \"*|*\"\ngroup[27].index \"0.4.0\"\ngroup[27].name \"top.0.4.0\"\ngroup[27].capacity 1.0\ngroup[27].partitions \"\"\ngroup[27].nodes[0].index 289\ngroup[27].nodes[0].retired false\ngroup[27].nodes[1].index 17\ngroup[27].nodes[1].retired false\ngroup[27].nodes[2].index 164\ngroup[27].nodes[2].retired false\ngroup[28].index \"0.4.1\"\ngroup[28].name \"top.0.4.1\"\ngroup[28].capacity 1.0\ngroup[28].partitions \"\"\ngroup[28].nodes[0].index 24\ngroup[28].nodes[0].retired false\ngroup[28].nodes[1].index 345\ngroup[28].nodes[1].retired false\ngroup[28].nodes[2].index 8\ngroup[28].nodes[2].retired false\ngroup[29].index \"0.4.2\"\ngroup[29].name \"top.0.4.2\"\ngroup[29].capacity 1.0\ngroup[29].partitions \"\"\ngroup[29].nodes[0].index 306\ngroup[29].nodes[0].retired false\ngroup[29].nodes[1].index 369\ngroup[29].nodes[1].retired false\ngroup[29].nodes[2].index 184\ngroup[29].nodes[2].retired false\ngroup[30].index \"0.4.3\"\ngroup[30].name \"top.0.4.3\"\ngroup[30].capacity 1.0\ngroup[30].partitions \"\"\ngroup[30].nodes[0].index 284\ngroup[30].nodes[0].retired false\ngroup[30].nodes[1].index 83\ngroup[30].nodes[1].retired false\ngroup[30].nodes[2].index 366\ngroup[30].nodes[2].retired false\ngroup[31].index \"0.4.4\"\ngroup[31].name \"top.0.4.4\"\ngroup[31].capacity 1.0\ngroup[31].partitions \"\"\ngroup[31].nodes[0].index 234\ngroup[31].nodes[0].retired false\ngroup[31].nodes[1].index 253\ngroup[31].nodes[1].retired false\ngroup[31].nodes[2].index 244\ngroup[31].nodes[2].retired false\ngroup[32].index \"1\"\ngroup[32].name \"top.1\"\ngroup[32].capacity 1.0\ngroup[32].partitions \"*|*\"\ngroup[33].index \"1.0\"\ngroup[33].name \"top.1.0\"\ngroup[33].capacity 1.0\ngroup[33].partitions \"*|*\"\ngroup[34].index \"1.0.0\"\ngroup[34].name \"top.1.0.0\"\ngroup[34].capacity 1.0\ngroup[34].partitions \"\"\ngroup[34].nodes[0].index 93\ngroup[34].nodes[0].retired false\ngroup[34].nodes[1].index 225\ngroup[34].nodes[1].retired false\ngroup[34].nodes[2].index 331\ngroup[34].nodes[2].retired false\ngroup[35].index \"1.0.1\"\ngroup[35].name \"top.1.0.1\"\ngroup[35].capacity 1.0\ngroup[35].partitions \"\"\ngroup[35].nodes[0].index 223\ngroup[35].nodes[0].retired false\ngroup[35].nodes[1].index 322\ngroup[35].nodes[1].retired false\ngroup[35].nodes[2].index 245\ngroup[35].nodes[2].retired false\ngroup[36].index \"1.0.2\"\ngroup[36].name \"top.1.0.2\"\ngroup[36].capacity 1.0\ngroup[36].partitions \"\"\ngroup[36].nodes[0].index 221\ngroup[36].nodes[0].retired false\ngroup[36].nodes[1].index 230\ngroup[36].nodes[1].retired false\ngroup[36].nodes[2].index 169\ngroup[36].nodes[2].retired false\ngroup[37].index \"1.0.3\"\ngroup[37].name \"top.1.0.3\"\ngroup[37].capacity 1.0\ngroup[37].partitions \"\"\ngroup[37].nodes[0].index 346\ngroup[37].nodes[0].retired false\ngroup[37].nodes[1].index 368\ngroup[37].nodes[1].retired false\ngroup[37].nodes[2].index 257\ngroup[37].nodes[2].retired false\ngroup[38].index \"1.0.4\"\ngroup[38].name \"top.1.0.4\"\ngroup[38].capacity 1.0\ngroup[38].partitions \"\"\ngroup[38].nodes[0].index 178\ngroup[38].nodes[0].retired false\ngroup[38].nodes[1].index 161\ngroup[38].nodes[1].retired false\ngroup[38].nodes[2].index 142\ngroup[38].nodes[2].retired false\ngroup[39].index \"1.1\"\ngroup[39].name \"top.1.1\"\ngroup[39].capacity 1.0\ngroup[39].partitions \"*|*\"\ngroup[40].index \"1.1.0\"\ngroup[40].name \"top.1.1.0\"\ngroup[40].capacity 1.0\ngroup[40].partitions \"\"\ngroup[40].nodes[0].index 105\ngroup[40].nodes[0].retired false\ngroup[40].nodes[1].index 152\ngroup[40].nodes[1].retired false\ngroup[40].nodes[2].index 371\ngroup[40].nodes[2].retired false\ngroup[41].index \"1.1.1\"\ngroup[41].name \"top.1.1.1\"\ngroup[41].capacity 1.0\ngroup[41].partitions \"\"\ngroup[41].nodes[0].index 330\ngroup[41].nodes[0].retired false\ngroup[41].nodes[1].index 13\ngroup[41].nodes[1].retired false\ngroup[41].nodes[2].index 125\ngroup[41].nodes[2].retired false\ngroup[42].index \"1.1.2\"\ngroup[42].name \"top.1.1.2\"\ngroup[42].capacity 1.0\ngroup[42].partitions \"\"\ngroup[42].nodes[0].index 10\ngroup[42].nodes[0].retired false\ngroup[42].nodes[1].index 356\ngroup[42].nodes[1].retired false\ngroup[42].nodes[2].index 45\ngroup[42].nodes[2].retired false\ngroup[43].index \"1.1.3\"\ngroup[43].name \"top.1.1.3\"\ngroup[43].capacity 1.0\ngroup[43].partitions \"\"\ngroup[43].nodes[0].index 241\ngroup[43].nodes[0].retired false\ngroup[43].nodes[1].index 145\ngroup[43].nodes[1].retired false\ngroup[43].nodes[2].index 246\ngroup[43].nodes[2].retired false\ngroup[44].index \"1.1.4\"\ngroup[44].name \"top.1.1.4\"\ngroup[44].capacity 1.0\ngroup[44].partitions \"\"\ngroup[44].nodes[0].index 37\ngroup[44].nodes[0].retired false\ngroup[44].nodes[1].index 204\ngroup[44].nodes[1].retired false\ngroup[44].nodes[2].index 110\ngroup[44].nodes[2].retired false\ngroup[45].index \"1.2\"\ngroup[45].name \"top.1.2\"\ngroup[45].capacity 1.0\ngroup[45].partitions \"*|*\"\ngroup[46].index \"1.2.0\"\ngroup[46].name \"top.1.2.0\"\ngroup[46].capacity 1.0\ngroup[46].partitions \"\"\ngroup[46].nodes[0].index 288\ngroup[46].nodes[0].retired false\ngroup[46].nodes[1].index 254\ngroup[46].nodes[1].retired false\ngroup[46].nodes[2].index 0\ngroup[46].nodes[2].retired false\ngroup[47].index \"1.2.1\"\ngroup[47].name \"top.1.2.1\"\ngroup[47].capacity 1.0\ngroup[47].partitions \"\"\ngroup[47].nodes[0].index 72\ngroup[47].nodes[0].retired false\ngroup[47].nodes[1].index 124\ngroup[47].nodes[1].retired false\ngroup[47].nodes[2].index 267\ngroup[47].nodes[2].retired false\ngroup[48].index \"1.2.2\"\ngroup[48].name \"top.1.2.2\"\ngroup[48].capacity 1.0\ngroup[48].partitions \"\"\ngroup[48].nodes[0].index 102\ngroup[48].nodes[0].retired false\ngroup[48].nodes[1].index 219\ngroup[48].nodes[1].retired false\ngroup[48].nodes[2].index 150\ngroup[48].nodes[2].retired false\ngroup[49].index \"1.2.3\"\ngroup[49].name \"top.1.2.3\"\ngroup[49].capacity 1.0\ngroup[49].partitions \"\"\ngroup[49].nodes[0].index 68\ngroup[49].nodes[0].retired false\ngroup[49].nodes[1].index 347\ngroup[49].nodes[1].retired false\ngroup[49].nodes[2].index 135\ngroup[49].nodes[2].retired false\ngroup[50].index \"1.2.4\"\ngroup[50].name \"top.1.2.4\"\ngroup[50].capacity 1.0\ngroup[50].partitions \"\"\ngroup[50].nodes[0].index 207\ngroup[50].nodes[0].retired false\ngroup[50].nodes[1].index 15\ngroup[50].nodes[1].retired false\ngroup[50].nodes[2].index 201\ngroup[50].nodes[2].retired false\ngroup[51].index \"1.3\"\ngroup[51].name \"top.1.3\"\ngroup[51].capacity 1.0\ngroup[51].partitions \"*|*\"\ngroup[52].index \"1.3.0\"\ngroup[52].name \"top.1.3.0\"\ngroup[52].capacity 1.0\ngroup[52].partitions \"\"\ngroup[52].nodes[0].index 134\ngroup[52].nodes[0].retired false\ngroup[52].nodes[1].index 293\ngroup[52].nodes[1].retired false\ngroup[52].nodes[2].index 167\ngroup[52].nodes[2].retired false\ngroup[53].index \"1.3.1\"\ngroup[53].name \"top.1.3.1\"\ngroup[53].capacity 1.0\ngroup[53].partitions \"\"\ngroup[53].nodes[0].index 199\ngroup[53].nodes[0].retired false\ngroup[53].nodes[1].index 123\ngroup[53].nodes[1].retired false\ngroup[53].nodes[2].index 277\ngroup[53].nodes[2].retired false\ngroup[54].index \"1.3.2\"\ngroup[54].name \"top.1.3.2\"\ngroup[54].capacity 1.0\ngroup[54].partitions \"\"\ngroup[54].nodes[0].index 127\ngroup[54].nodes[0].retired false\ngroup[54].nodes[1].index 309\ngroup[54].nodes[1].retired false\ngroup[54].nodes[2].index 266\ngroup[54].nodes[2].retired false\ngroup[55].index \"1.3.3\"\ngroup[55].name \"top.1.3.3\"\ngroup[55].capacity 1.0\ngroup[55].partitions \"\"\ngroup[55].nodes[0].index 198\ngroup[55].nodes[0].retired false\ngroup[55].nodes[1].index 294\ngroup[55].nodes[1].retired false\ngroup[55].nodes[2].index 263\ngroup[55].nodes[2].retired false\ngroup[56].index \"1.3.4\"\ngroup[56].name \"top.1.3.4\"\ngroup[56].capacity 1.0\ngroup[56].partitions \"\"\ngroup[56].nodes[0].index 71\ngroup[56].nodes[0].retired false\ngroup[56].nodes[1].index 65\ngroup[56].nodes[1].retired false\ngroup[56].nodes[2].index 220\ngroup[56].nodes[2].retired false\ngroup[57].index \"1.4\"\ngroup[57].name \"top.1.4\"\ngroup[57].capacity 1.0\ngroup[57].partitions \"*|*\"\ngroup[58].index \"1.4.0\"\ngroup[58].name \"top.1.4.0\"\ngroup[58].capacity 1.0\ngroup[58].partitions \"\"\ngroup[58].nodes[0].index 121\ngroup[58].nodes[0].retired false\ngroup[58].nodes[1].index 4\ngroup[58].nodes[1].retired false\ngroup[58].nodes[2].index 265\ngroup[58].nodes[2].retired false\ngroup[59].index \"1.4.1\"\ngroup[59].name \"top.1.4.1\"\ngroup[59].capacity 1.0\ngroup[59].partitions \"\"\ngroup[59].nodes[0].index 58\ngroup[59].nodes[0].retired false\ngroup[59].nodes[1].index 210\ngroup[59].nodes[1].retired false\ngroup[59].nodes[2].index 53\ngroup[59].nodes[2].retired false\ngroup[60].index \"1.4.2\"\ngroup[60].name \"top.1.4.2\"\ngroup[60].capacity 1.0\ngroup[60].partitions \"\"\ngroup[60].nodes[0].index 19\ngroup[60].nodes[0].retired false\ngroup[60].nodes[1].index 367\ngroup[60].nodes[1].retired false\ngroup[60].nodes[2].index 101\ngroup[60].nodes[2].retired false\ngroup[61].index \"1.4.3\"\ngroup[61].name \"top.1.4.3\"\ngroup[61].capacity 1.0\ngroup[61].partitions \"\"\ngroup[61].nodes[0].index 20\ngroup[61].nodes[0].retired false\ngroup[61].nodes[1].index 242\ngroup[61].nodes[1].retired false\ngroup[61].nodes[2].index 268\ngroup[61].nodes[2].retired false\ngroup[62].index \"1.4.4\"\ngroup[62].name \"top.1.4.4\"\ngroup[62].capacity 1.0\ngroup[62].partitions \"\"\ngroup[62].nodes[0].index 200\ngroup[62].nodes[0].retired false\ngroup[62].nodes[1].index 21\ngroup[62].nodes[1].retired false\ngroup[62].nodes[2].index 279\ngroup[62].nodes[2].retired false\ngroup[63].index \"2\"\ngroup[63].name \"top.2\"\ngroup[63].capacity 1.0\ngroup[63].partitions \"*|*\"\ngroup[64].index \"2.0\"\ngroup[64].name \"top.2.0\"\ngroup[64].capacity 1.0\ngroup[64].partitions \"*|*\"\ngroup[65].index \"2.0.0\"\ngroup[65].name \"top.2.0.0\"\ngroup[65].capacity 1.0\ngroup[65].partitions \"\"\ngroup[65].nodes[0].index 182\ngroup[65].nodes[0].retired false\ngroup[65].nodes[1].index 78\ngroup[65].nodes[1].retired false\ngroup[65].nodes[2].index 158\ngroup[65].nodes[2].retired false\ngroup[66].index \"2.0.1\"\ngroup[66].name \"top.2.0.1\"\ngroup[66].capacity 1.0\ngroup[66].partitions \"\"\ngroup[66].nodes[0].index 27\ngroup[66].nodes[0].retired false\ngroup[66].nodes[1].index 50\ngroup[66].nodes[1].retired false\ngroup[66].nodes[2].index 217\ngroup[66].nodes[2].retired false\ngroup[67].index \"2.0.2\"\ngroup[67].name \"top.2.0.2\"\ngroup[67].capacity 1.0\ngroup[67].partitions \"\"\ngroup[67].nodes[0].index 248\ngroup[67].nodes[0].retired false\ngroup[67].nodes[1].index 319\ngroup[67].nodes[1].retired false\ngroup[67].nodes[2].index 116\ngroup[67].nodes[2].retired false\ngroup[68].index \"2.0.3\"\ngroup[68].name \"top.2.0.3\"\ngroup[68].capacity 1.0\ngroup[68].partitions \"\"\ngroup[68].nodes[0].index 29\ngroup[68].nodes[0].retired false\ngroup[68].nodes[1].index 211\ngroup[68].nodes[1].retired false\ngroup[68].nodes[2].index 365\ngroup[68].nodes[2].retired false\ngroup[69].index \"2.0.4\"\ngroup[69].name \"top.2.0.4\"\ngroup[69].capacity 1.0\ngroup[69].partitions \"\"\ngroup[69].nodes[0].index 300\ngroup[69].nodes[0].retired false\ngroup[69].nodes[1].index 81\ngroup[69].nodes[1].retired false\ngroup[69].nodes[2].index 192\ngroup[69].nodes[2].retired false\ngroup[70].index \"2.1\"\ngroup[70].name \"top.2.1\"\ngroup[70].capacity 1.0\ngroup[70].partitions \"*|*\"\ngroup[71].index \"2.1.0\"\ngroup[71].name \"top.2.1.0\"\ngroup[71].capacity 1.0\ngroup[71].partitions \"\"\ngroup[71].nodes[0].index 151\ngroup[71].nodes[0].retired false\ngroup[71].nodes[1].index 133\ngroup[71].nodes[1].retired false\ngroup[71].nodes[2].index 344\ngroup[71].nodes[2].retired false\ngroup[72].index \"2.1.1\"\ngroup[72].name \"top.2.1.1\"\ngroup[72].capacity 1.0\ngroup[72].partitions \"\"\ngroup[72].nodes[0].index 120\ngroup[72].nodes[0].retired false\ngroup[72].nodes[1].index 195\ngroup[72].nodes[1].retired false\ngroup[72].nodes[2].index 215\ngroup[72].nodes[2].retired false\ngroup[73].index \"2.1.2\"\ngroup[73].name \"top.2.1.2\"\ngroup[73].capacity 1.0\ngroup[73].partitions \"\"\ngroup[73].nodes[0].index 250\ngroup[73].nodes[0].retired false\ngroup[73].nodes[1].index 143\ngroup[73].nodes[1].retired false\ngroup[73].nodes[2].index 183\ngroup[73].nodes[2].retired false\ngroup[74].index \"2.1.3\"\ngroup[74].name \"top.2.1.3\"\ngroup[74].capacity 1.0\ngroup[74].partitions \"\"\ngroup[74].nodes[0].index 301\ngroup[74].nodes[0].retired false\ngroup[74].nodes[1].index 291\ngroup[74].nodes[1].retired false\ngroup[74].nodes[2].index 333\ngroup[74].nodes[2].retired false\ngroup[75].index \"2.1.4\"\ngroup[75].name \"top.2.1.4\"\ngroup[75].capacity 1.0\ngroup[75].partitions \"\"\ngroup[75].nodes[0].index 315\ngroup[75].nodes[0].retired false\ngroup[75].nodes[1].index 26\ngroup[75].nodes[1].retired false\ngroup[75].nodes[2].index 249\ngroup[75].nodes[2].retired false\ngroup[76].index \"2.2\"\ngroup[76].name \"top.2.2\"\ngroup[76].capacity 1.0\ngroup[76].partitions \"*|*\"\ngroup[77].index \"2.2.0\"\ngroup[77].name \"top.2.2.0\"\ngroup[77].capacity 1.0\ngroup[77].partitions \"\"\ngroup[77].nodes[0].index 360\ngroup[77].nodes[0].retired false\ngroup[77].nodes[1].index 172\ngroup[77].nodes[1].retired false\ngroup[77].nodes[2].index 326\ngroup[77].nodes[2].retired false\ngroup[78].index \"2.2.1\"\ngroup[78].name \"top.2.2.1\"\ngroup[78].capacity 1.0\ngroup[78].partitions \"\"\ngroup[78].nodes[0].index 262\ngroup[78].nodes[0].retired false\ngroup[78].nodes[1].index 115\ngroup[78].nodes[1].retired false\ngroup[78].nodes[2].index 310\ngroup[78].nodes[2].retired false\ngroup[79].index \"2.2.2\"\ngroup[79].name \"top.2.2.2\"\ngroup[79].capacity 1.0\ngroup[79].partitions \"\"\ngroup[79].nodes[0].index 303\ngroup[79].nodes[0].retired false\ngroup[79].nodes[1].index 307\ngroup[79].nodes[1].retired false\ngroup[79].nodes[2].index 348\ngroup[79].nodes[2].retired false\ngroup[80].index \"2.2.3\"\ngroup[80].name \"top.2.2.3\"\ngroup[80].capacity 1.0\ngroup[80].partitions \"\"\ngroup[80].nodes[0].index 227\ngroup[80].nodes[0].retired false\ngroup[80].nodes[1].index 91\ngroup[80].nodes[1].retired false\ngroup[80].nodes[2].index 282\ngroup[80].nodes[2].retired false\ngroup[81].index \"2.2.4\"\ngroup[81].name \"top.2.2.4\"\ngroup[81].capacity 1.0\ngroup[81].partitions \"\"\ngroup[81].nodes[0].index 354\ngroup[81].nodes[0].retired false\ngroup[81].nodes[1].index 190\ngroup[81].nodes[1].retired false\ngroup[81].nodes[2].index 238\ngroup[81].nodes[2].retired false\ngroup[82].index \"2.3\"\ngroup[82].name \"top.2.3\"\ngroup[82].capacity 1.0\ngroup[82].partitions \"*|*\"\ngroup[83].index \"2.3.0\"\ngroup[83].name \"top.2.3.0\"\ngroup[83].capacity 1.0\ngroup[83].partitions \"\"\ngroup[83].nodes[0].index 185\ngroup[83].nodes[0].retired false\ngroup[83].nodes[1].index 264\ngroup[83].nodes[1].retired false\ngroup[83].nodes[2].index 39\ngroup[83].nodes[2].retired false\ngroup[84].index \"2.3.1\"\ngroup[84].name \"top.2.3.1\"\ngroup[84].capacity 1.0\ngroup[84].partitions \"\"\ngroup[84].nodes[0].index 235\ngroup[84].nodes[0].retired false\ngroup[84].nodes[1].index 339\ngroup[84].nodes[1].retired false\ngroup[84].nodes[2].index 327\ngroup[84].nodes[2].retired false\ngroup[85].index \"2.3.2\"\ngroup[85].name \"top.2.3.2\"\ngroup[85].capacity 1.0\ngroup[85].partitions \"\"\ngroup[85].nodes[0].index 299\ngroup[85].nodes[0].retired false\ngroup[85].nodes[1].index 180\ngroup[85].nodes[1].retired false\ngroup[85].nodes[2].index 194\ngroup[85].nodes[2].retired false\ngroup[86].index \"2.3.3\"\ngroup[86].name \"top.2.3.3\"\ngroup[86].capacity 1.0\ngroup[86].partitions \"\"\ngroup[86].nodes[0].index 6\ngroup[86].nodes[0].retired false\ngroup[86].nodes[1].index 57\ngroup[86].nodes[1].retired false\ngroup[86].nodes[2].index 260\ngroup[86].nodes[2].retired false\ngroup[87].index \"2.3.4\"\ngroup[87].name \"top.2.3.4\"\ngroup[87].capacity 1.0\ngroup[87].partitions \"\"\ngroup[87].nodes[0].index 216\ngroup[87].nodes[0].retired false\ngroup[87].nodes[1].index 193\ngroup[87].nodes[1].retired false\ngroup[87].nodes[2].index 290\ngroup[87].nodes[2].retired false\ngroup[88].index \"2.4\"\ngroup[88].name \"top.2.4\"\ngroup[88].capacity 1.0\ngroup[88].partitions \"*|*\"\ngroup[89].index \"2.4.0\"\ngroup[89].name \"top.2.4.0\"\ngroup[89].capacity 1.0\ngroup[89].partitions \"\"\ngroup[89].nodes[0].index 332\ngroup[89].nodes[0].retired false\ngroup[89].nodes[1].index 107\ngroup[89].nodes[1].retired false\ngroup[89].nodes[2].index 176\ngroup[89].nodes[2].retired false\ngroup[90].index \"2.4.1\"\ngroup[90].name \"top.2.4.1\"\ngroup[90].capacity 1.0\ngroup[90].partitions \"\"\ngroup[90].nodes[0].index 233\ngroup[90].nodes[0].retired false\ngroup[90].nodes[1].index 196\ngroup[90].nodes[1].retired false\ngroup[90].nodes[2].index 157\ngroup[90].nodes[2].retired false\ngroup[91].index \"2.4.2\"\ngroup[91].name \"top.2.4.2\"\ngroup[91].capacity 1.0\ngroup[91].partitions \"\"\ngroup[91].nodes[0].index 285\ngroup[91].nodes[0].retired false\ngroup[91].nodes[1].index 98\ngroup[91].nodes[1].retired false\ngroup[91].nodes[2].index 44\ngroup[91].nodes[2].retired false\ngroup[92].index \"2.4.3\"\ngroup[92].name \"top.2.4.3\"\ngroup[92].capacity 1.0\ngroup[92].partitions \"\"\ngroup[92].nodes[0].index 155\ngroup[92].nodes[0].retired false\ngroup[92].nodes[1].index 370\ngroup[92].nodes[1].retired false\ngroup[92].nodes[2].index 218\ngroup[92].nodes[2].retired false\ngroup[93].index \"2.4.4\"\ngroup[93].name \"top.2.4.4\"\ngroup[93].capacity 1.0\ngroup[93].partitions \"\"\ngroup[93].nodes[0].index 162\ngroup[93].nodes[0].retired false\ngroup[93].nodes[1].index 231\ngroup[93].nodes[1].retired false\ngroup[93].nodes[2].index 191\ngroup[93].nodes[2].retired false\ngroup[94].index \"3\"\ngroup[94].name \"top.3\"\ngroup[94].capacity 1.0\ngroup[94].partitions \"*|*\"\ngroup[95].index \"3.0\"\ngroup[95].name \"top.3.0\"\ngroup[95].capacity 1.0\ngroup[95].partitions \"*|*\"\ngroup[96].index \"3.0.0\"\ngroup[96].name \"top.3.0.0\"\ngroup[96].capacity 1.0\ngroup[96].partitions \"\"\ngroup[96].nodes[0].index 213\ngroup[96].nodes[0].retired false\ngroup[96].nodes[1].index 148\ngroup[96].nodes[1].retired false\ngroup[96].nodes[2].index 42\ngroup[96].nodes[2].retired false\ngroup[97].index \"3.0.1\"\ngroup[97].name \"top.3.0.1\"\ngroup[97].capacity 1.0\ngroup[97].partitions \"\"\ngroup[97].nodes[0].index 247\ngroup[97].nodes[0].retired false\ngroup[97].nodes[1].index 11\ngroup[97].nodes[1].retired false\ngroup[97].nodes[2].index 352\ngroup[97].nodes[2].retired false\ngroup[98].index \"3.0.2\"\ngroup[98].name \"top.3.0.2\"\ngroup[98].capacity 1.0\ngroup[98].partitions \"\"\ngroup[98].nodes[0].index 66\ngroup[98].nodes[0].retired false\ngroup[98].nodes[1].index 208\ngroup[98].nodes[1].retired false\ngroup[98].nodes[2].index 316\ngroup[98].nodes[2].retired false\ngroup[99].index \"3.0.3\"\ngroup[99].name \"top.3.0.3\"\ngroup[99].capacity 1.0\ngroup[99].partitions \"\"\ngroup[99].nodes[0].index 205\ngroup[99].nodes[0].retired false\ngroup[99].nodes[1].index 292\ngroup[99].nodes[1].retired false\ngroup[99].nodes[2].index 80\ngroup[99].nodes[2].retired false\ngroup[100].index \"3.0.4\"\ngroup[100].name \"top.3.0.4\"\ngroup[100].capacity 1.0\ngroup[100].partitions \"\"\ngroup[100].nodes[0].index 106\ngroup[100].nodes[0].retired false\ngroup[100].nodes[1].index 302\ngroup[100].nodes[1].retired false\ngroup[100].nodes[2].index 308\ngroup[100].nodes[2].retired false\ngroup[101].index \"3.1\"\ngroup[101].name \"top.3.1\"\ngroup[101].capacity 1.0\ngroup[101].partitions \"*|*\"\ngroup[102].index \"3.1.0\"\ngroup[102].name \"top.3.1.0\"\ngroup[102].capacity 1.0\ngroup[102].partitions \"\"\ngroup[102].nodes[0].index 312\ngroup[102].nodes[0].retired false\ngroup[102].nodes[1].index 323\ngroup[102].nodes[1].retired false\ngroup[102].nodes[2].index 278\ngroup[102].nodes[2].retired false\ngroup[103].index \"3.1.1\"\ngroup[103].name \"top.3.1.1\"\ngroup[103].capacity 1.0\ngroup[103].partitions \"\"\ngroup[103].nodes[0].index 146\ngroup[103].nodes[0].retired false\ngroup[103].nodes[1].index 197\ngroup[103].nodes[1].retired false\ngroup[103].nodes[2].index 358\ngroup[103].nodes[2].retired false\ngroup[104].index \"3.1.2\"\ngroup[104].name \"top.3.1.2\"\ngroup[104].capacity 1.0\ngroup[104].partitions \"\"\ngroup[104].nodes[0].index 239\ngroup[104].nodes[0].retired false\ngroup[104].nodes[1].index 305\ngroup[104].nodes[1].retired false\ngroup[104].nodes[2].index 165\ngroup[104].nodes[2].retired false\ngroup[105].index \"3.1.3\"\ngroup[105].name \"top.3.1.3\"\ngroup[105].capacity 1.0\ngroup[105].partitions \"\"\ngroup[105].nodes[0].index 49\ngroup[105].nodes[0].retired false\ngroup[105].nodes[1].index 25\ngroup[105].nodes[1].retired false\ngroup[105].nodes[2].index 36\ngroup[105].nodes[2].retired false\ngroup[106].index \"3.1.4\"\ngroup[106].name \"top.3.1.4\"\ngroup[106].capacity 1.0\ngroup[106].partitions \"\"\ngroup[106].nodes[0].index 229\ngroup[106].nodes[0].retired false\ngroup[106].nodes[1].index 73\ngroup[106].nodes[1].retired false\ngroup[106].nodes[2].index 311\ngroup[106].nodes[2].retired false\ngroup[107].index \"3.2\"\ngroup[107].name \"top.3.2\"\ngroup[107].capacity 1.0\ngroup[107].partitions \"*|*\"\ngroup[108].index \"3.2.0\"\ngroup[108].name \"top.3.2.0\"\ngroup[108].capacity 1.0\ngroup[108].partitions \"\"\ngroup[108].nodes[0].index 103\ngroup[108].nodes[0].retired false\ngroup[108].nodes[1].index 163\ngroup[108].nodes[1].retired false\ngroup[108].nodes[2].index 51\ngroup[108].nodes[2].retired false\ngroup[109].index \"3.2.1\"\ngroup[109].name \"top.3.2.1\"\ngroup[109].capacity 1.0\ngroup[109].partitions \"\"\ngroup[109].nodes[0].index 12\ngroup[109].nodes[0].retired false\ngroup[109].nodes[1].index 52\ngroup[109].nodes[1].retired false\ngroup[109].nodes[2].index 203\ngroup[109].nodes[2].retired false\ngroup[110].index \"3.2.2\"\ngroup[110].name \"top.3.2.2\"\ngroup[110].capacity 1.0\ngroup[110].partitions \"\"\ngroup[110].nodes[0].index 59\ngroup[110].nodes[0].retired false\ngroup[110].nodes[1].index 361\ngroup[110].nodes[1].retired false\ngroup[110].nodes[2].index 35\ngroup[110].nodes[2].retired false\ngroup[111].index \"3.2.3\"\ngroup[111].name \"top.3.2.3\"\ngroup[111].capacity 1.0\ngroup[111].partitions \"\"\ngroup[111].nodes[0].index 136\ngroup[111].nodes[0].retired false\ngroup[111].nodes[1].index 9\ngroup[111].nodes[1].retired false\ngroup[111].nodes[2].index 258\ngroup[111].nodes[2].retired false\ngroup[112].index \"3.2.4\"\ngroup[112].name \"top.3.2.4\"\ngroup[112].capacity 1.0\ngroup[112].partitions \"\"\ngroup[112].nodes[0].index 95\ngroup[112].nodes[0].retired false\ngroup[112].nodes[1].index 177\ngroup[112].nodes[1].retired false\ngroup[112].nodes[2].index 5\ngroup[112].nodes[2].retired false\ngroup[113].index \"3.3\"\ngroup[113].name \"top.3.3\"\ngroup[113].capacity 1.0\ngroup[113].partitions \"*|*\"\ngroup[114].index \"3.3.0\"\ngroup[114].name \"top.3.3.0\"\ngroup[114].capacity 1.0\ngroup[114].partitions \"\"\ngroup[114].nodes[0].index 77\ngroup[114].nodes[0].retired false\ngroup[114].nodes[1].index 202\ngroup[114].nodes[1].retired false\ngroup[114].nodes[2].index 67\ngroup[114].nodes[2].retired false\ngroup[115].index \"3.3.1\"\ngroup[115].name \"top.3.3.1\"\ngroup[115].capacity 1.0\ngroup[115].partitions \"\"\ngroup[115].nodes[0].index 259\ngroup[115].nodes[0].retired false\ngroup[115].nodes[1].index 28\ngroup[115].nodes[1].retired false\ngroup[115].nodes[2].index 40\ngroup[115].nodes[2].retired false\ngroup[116].index \"3.3.2\"\ngroup[116].name \"top.3.3.2\"\ngroup[116].capacity 1.0\ngroup[116].partitions \"\"\ngroup[116].nodes[0].index 89\ngroup[116].nodes[0].retired false\ngroup[116].nodes[1].index 46\ngroup[116].nodes[1].retired false\ngroup[116].nodes[2].index 341\ngroup[116].nodes[2].retired false\ngroup[117].index \"3.3.3\"\ngroup[117].name \"top.3.3.3\"\ngroup[117].capacity 1.0\ngroup[117].partitions \"\"\ngroup[117].nodes[0].index 118\ngroup[117].nodes[0].retired false\ngroup[117].nodes[1].index 335\ngroup[117].nodes[1].retired false\ngroup[117].nodes[2].index 1\ngroup[117].nodes[2].retired false\ngroup[118].index \"3.3.4\"\ngroup[118].name \"top.3.3.4\"\ngroup[118].capacity 1.0\ngroup[118].partitions \"\"\ngroup[118].nodes[0].index 87\ngroup[118].nodes[0].retired false\ngroup[118].nodes[1].index 147\ngroup[118].nodes[1].retired false\ngroup[118].nodes[2].index 336\ngroup[118].nodes[2].retired false\ngroup[119].index \"3.4\"\ngroup[119].name \"top.3.4\"\ngroup[119].capacity 1.0\ngroup[119].partitions \"*|*\"\ngroup[120].index \"3.4.0\"\ngroup[120].name \"top.3.4.0\"\ngroup[120].capacity 1.0\ngroup[120].partitions \"\"\ngroup[120].nodes[0].index 353\ngroup[120].nodes[0].retired false\ngroup[120].nodes[1].index 168\ngroup[120].nodes[1].retired false\ngroup[120].nodes[2].index 114\ngroup[120].nodes[2].retired false\ngroup[121].index \"3.4.1\"\ngroup[121].name \"top.3.4.1\"\ngroup[121].capacity 1.0\ngroup[121].partitions \"\"\ngroup[121].nodes[0].index 104\ngroup[121].nodes[0].retired false\ngroup[121].nodes[1].index 287\ngroup[121].nodes[1].retired false\ngroup[121].nodes[2].index 222\ngroup[121].nodes[2].retired false\ngroup[122].index \"3.4.2\"\ngroup[122].name \"top.3.4.2\"\ngroup[122].capacity 1.0\ngroup[122].partitions \"\"\ngroup[122].nodes[0].index 325\ngroup[122].nodes[0].retired false\ngroup[122].nodes[1].index 240\ngroup[122].nodes[1].retired false\ngroup[122].nodes[2].index 296\ngroup[122].nodes[2].retired false\ngroup[123].index \"3.4.3\"\ngroup[123].name \"top.3.4.3\"\ngroup[123].capacity 1.0\ngroup[123].partitions \"\"\ngroup[123].nodes[0].index 166\ngroup[123].nodes[0].retired false\ngroup[123].nodes[1].index 141\ngroup[123].nodes[1].retired false\ngroup[123].nodes[2].index 23\ngroup[123].nodes[2].retired false\ngroup[124].index \"3.4.4\"\ngroup[124].name \"top.3.4.4\"\ngroup[124].capacity 1.0\ngroup[124].partitions \"\"\ngroup[124].nodes[0].index 100\ngroup[124].nodes[0].retired false\ngroup[124].nodes[1].index 320\ngroup[124].nodes[1].retired false\ngroup[124].nodes[2].index 96\ngroup[124].nodes[2].retired false\ngroup[125].index \"4\"\ngroup[125].name \"top.4\"\ngroup[125].capacity 1.0\ngroup[125].partitions \"*|*\"\ngroup[126].index \"4.0\"\ngroup[126].name \"top.4.0\"\ngroup[126].capacity 1.0\ngroup[126].partitions \"*|*\"\ngroup[127].index \"4.0.0\"\ngroup[127].name \"top.4.0.0\"\ngroup[127].capacity 1.0\ngroup[127].partitions \"\"\ngroup[127].nodes[0].index 18\ngroup[127].nodes[0].retired false\ngroup[127].nodes[1].index 75\ngroup[127].nodes[1].retired false\ngroup[127].nodes[2].index 79\ngroup[127].nodes[2].retired false\ngroup[128].index \"4.0.1\"\ngroup[128].name \"top.4.0.1\"\ngroup[128].capacity 1.0\ngroup[128].partitions \"\"\ngroup[128].nodes[0].index 328\ngroup[128].nodes[0].retired false\ngroup[128].nodes[1].index 61\ngroup[128].nodes[1].retired false\ngroup[128].nodes[2].index 334\ngroup[128].nodes[2].retired false\ngroup[129].index \"4.0.2\"\ngroup[129].name \"top.4.0.2\"\ngroup[129].capacity 1.0\ngroup[129].partitions \"\"\ngroup[129].nodes[0].index 363\ngroup[129].nodes[0].retired false\ngroup[129].nodes[1].index 275\ngroup[129].nodes[1].retired false\ngroup[129].nodes[2].index 343\ngroup[129].nodes[2].retired false\ngroup[130].index \"4.0.3\"\ngroup[130].name \"top.4.0.3\"\ngroup[130].capacity 1.0\ngroup[130].partitions \"\"\ngroup[130].nodes[0].index 252\ngroup[130].nodes[0].retired false\ngroup[130].nodes[1].index 297\ngroup[130].nodes[1].retired false\ngroup[130].nodes[2].index 34\ngroup[130].nodes[2].retired false\ngroup[131].index \"4.0.4\"\ngroup[131].name \"top.4.0.4\"\ngroup[131].capacity 1.0\ngroup[131].partitions \"\"\ngroup[131].nodes[0].index 280\ngroup[131].nodes[0].retired false\ngroup[131].nodes[1].index 174\ngroup[131].nodes[1].retired false\ngroup[131].nodes[2].index 272\ngroup[131].nodes[2].retired false\ngroup[132].index \"4.1\"\ngroup[132].name \"top.4.1\"\ngroup[132].capacity 1.0\ngroup[132].partitions \"*|*\"\ngroup[133].index \"4.1.0\"\ngroup[133].name \"top.4.1.0\"\ngroup[133].capacity 1.0\ngroup[133].partitions \"\"\ngroup[133].nodes[0].index 128\ngroup[133].nodes[0].retired false\ngroup[133].nodes[1].index 187\ngroup[133].nodes[1].retired false\ngroup[133].nodes[2].index 313\ngroup[133].nodes[2].retired false\ngroup[134].index \"4.1.1\"\ngroup[134].name \"top.4.1.1\"\ngroup[134].capacity 1.0\ngroup[134].partitions \"\"\ngroup[134].nodes[0].index 92\ngroup[134].nodes[0].retired false\ngroup[134].nodes[1].index 351\ngroup[134].nodes[1].retired false\ngroup[134].nodes[2].index 122\ngroup[134].nodes[2].retired false\ngroup[135].index \"4.1.2\"\ngroup[135].name \"top.4.1.2\"\ngroup[135].capacity 1.0\ngroup[135].partitions \"\"\ngroup[135].nodes[0].index 362\ngroup[135].nodes[0].retired false\ngroup[135].nodes[1].index 156\ngroup[135].nodes[1].retired false\ngroup[135].nodes[2].index 186\ngroup[135].nodes[2].retired false\ngroup[136].index \"4.1.3\"\ngroup[136].name \"top.4.1.3\"\ngroup[136].capacity 1.0\ngroup[136].partitions \"\"\ngroup[136].nodes[0].index 129\ngroup[136].nodes[0].retired false\ngroup[136].nodes[1].index 159\ngroup[136].nodes[1].retired false\ngroup[136].nodes[2].index 357\ngroup[136].nodes[2].retired false\ngroup[137].index \"4.1.4\"\ngroup[137].name \"top.4.1.4\"\ngroup[137].capacity 1.0\ngroup[137].partitions \"\"\ngroup[137].nodes[0].index 140\ngroup[137].nodes[0].retired false\ngroup[137].nodes[1].index 2\ngroup[137].nodes[1].retired false\ngroup[137].nodes[2].index 7\ngroup[137].nodes[2].retired false\ngroup[138].index \"4.2\"\ngroup[138].name \"top.4.2\"\ngroup[138].capacity 1.0\ngroup[138].partitions \"*|*\"\ngroup[139].index \"4.2.0\"\ngroup[139].name \"top.4.2.0\"\ngroup[139].capacity 1.0\ngroup[139].partitions \"\"\ngroup[139].nodes[0].index 108\ngroup[139].nodes[0].retired false\ngroup[139].nodes[1].index 276\ngroup[139].nodes[1].retired false\ngroup[139].nodes[2].index 126\ngroup[139].nodes[2].retired false\ngroup[140].index \"4.2.1\"\ngroup[140].name \"top.4.2.1\"\ngroup[140].capacity 1.0\ngroup[140].partitions \"\"\ngroup[140].nodes[0].index 188\ngroup[140].nodes[0].retired false\ngroup[140].nodes[1].index 281\ngroup[140].nodes[1].retired false\ngroup[140].nodes[2].index 137\ngroup[140].nodes[2].retired false\ngroup[141].index \"4.2.2\"\ngroup[141].name \"top.4.2.2\"\ngroup[141].capacity 1.0\ngroup[141].partitions \"\"\ngroup[141].nodes[0].index 175\ngroup[141].nodes[0].retired false\ngroup[141].nodes[1].index 364\ngroup[141].nodes[1].retired false\ngroup[141].nodes[2].index 117\ngroup[141].nodes[2].retired false\ngroup[142].index \"4.2.3\"\ngroup[142].name \"top.4.2.3\"\ngroup[142].capacity 1.0\ngroup[142].partitions \"\"\ngroup[142].nodes[0].index 14\ngroup[142].nodes[0].retired false\ngroup[142].nodes[1].index 373\ngroup[142].nodes[1].retired false\ngroup[142].nodes[2].index 132\ngroup[142].nodes[2].retired false\ngroup[143].index \"4.2.4\"\ngroup[143].name \"top.4.2.4\"\ngroup[143].capacity 1.0\ngroup[143].partitions \"\"\ngroup[143].nodes[0].index 338\ngroup[143].nodes[0].retired false\ngroup[143].nodes[1].index 54\ngroup[143].nodes[1].retired false\ngroup[143].nodes[2].index 209\ngroup[143].nodes[2].retired false\ngroup[144].index \"4.3\"\ngroup[144].name \"top.4.3\"\ngroup[144].capacity 1.0\ngroup[144].partitions \"*|*\"\ngroup[145].index \"4.3.0\"\ngroup[145].name \"top.4.3.0\"\ngroup[145].capacity 1.0\ngroup[145].partitions \"\"\ngroup[145].nodes[0].index 226\ngroup[145].nodes[0].retired false\ngroup[145].nodes[1].index 38\ngroup[145].nodes[1].retired false\ngroup[145].nodes[2].index 318\ngroup[145].nodes[2].retired false\ngroup[146].index \"4.3.1\"\ngroup[146].name \"top.4.3.1\"\ngroup[146].capacity 1.0\ngroup[146].partitions \"\"\ngroup[146].nodes[0].index 283\ngroup[146].nodes[0].retired false\ngroup[146].nodes[1].index 109\ngroup[146].nodes[1].retired false\ngroup[146].nodes[2].index 171\ngroup[146].nodes[2].retired false\ngroup[147].index \"4.3.2\"\ngroup[147].name \"top.4.3.2\"\ngroup[147].capacity 1.0\ngroup[147].partitions \"\"\ngroup[147].nodes[0].index 130\ngroup[147].nodes[0].retired false\ngroup[147].nodes[1].index 119\ngroup[147].nodes[1].retired false\ngroup[147].nodes[2].index 206\ngroup[147].nodes[2].retired false\ngroup[148].index \"4.3.3\"\ngroup[148].name \"top.4.3.3\"\ngroup[148].capacity 1.0\ngroup[148].partitions \"\"\ngroup[148].nodes[0].index 295\ngroup[148].nodes[0].retired false\ngroup[148].nodes[1].index 154\ngroup[148].nodes[1].retired false\ngroup[148].nodes[2].index 298\ngroup[148].nodes[2].retired false\ngroup[149].index \"4.3.4\"\ngroup[149].name \"top.4.3.4\"\ngroup[149].capacity 1.0\ngroup[149].partitions \"\"\ngroup[149].nodes[0].index 273\ngroup[149].nodes[0].retired false\ngroup[149].nodes[1].index 16\ngroup[149].nodes[1].retired false\ngroup[149].nodes[2].index 329\ngroup[149].nodes[2].retired false\ngroup[150].index \"4.4\"\ngroup[150].name \"top.4.4\"\ngroup[150].capacity 1.0\ngroup[150].partitions \"*|*\"\ngroup[151].index \"4.4.0\"\ngroup[151].name \"top.4.4.0\"\ngroup[151].capacity 1.0\ngroup[151].partitions \"\"\ngroup[151].nodes[0].index 237\ngroup[151].nodes[0].retired false\ngroup[151].nodes[1].index 85\ngroup[151].nodes[1].retired false\ngroup[151].nodes[2].index 3\ngroup[151].nodes[2].retired false\ngroup[152].index \"4.4.1\"\ngroup[152].name \"top.4.4.1\"\ngroup[152].capacity 1.0\ngroup[152].partitions \"\"\ngroup[152].nodes[0].index 62\ngroup[152].nodes[0].retired false\ngroup[152].nodes[1].index 224\ngroup[152].nodes[1].retired false\ngroup[152].nodes[2].index 113\ngroup[152].nodes[2].retired false\ngroup[153].index \"4.4.2\"\ngroup[153].name \"top.4.4.2\"\ngroup[153].capacity 1.0\ngroup[153].partitions \"\"\ngroup[153].nodes[0].index 179\ngroup[153].nodes[0].retired false\ngroup[153].nodes[1].index 41\ngroup[153].nodes[1].retired false\ngroup[153].nodes[2].index 342\ngroup[153].nodes[2].retired false\ngroup[154].index \"4.4.3\"\ngroup[154].name \"top.4.4.3\"\ngroup[154].capacity 1.0\ngroup[154].partitions \"\"\ngroup[154].nodes[0].index 304\ngroup[154].nodes[0].retired false\ngroup[154].nodes[1].index 138\ngroup[154].nodes[1].retired false\ngroup[154].nodes[2].index 97\ngroup[154].nodes[2].retired false\ngroup[155].index \"4.4.4\"\ngroup[155].name \"top.4.4.4\"\ngroup[155].capacity 1.0\ngroup[155].partitions \"\"\ngroup[155].nodes[0].index 270\ngroup[155].nodes[0].retired false\ngroup[155].nodes[1].index 256\ngroup[155].nodes[1].retired false\ngroup[155].nodes[2].index 271\ngroup[155].nodes[2].retired false\ndisk_distribution MODULO_BID",
+ "node-type": "distributor",
+ "redundancy": 3,
+ "node-count": 500,
+ "up-states": "uim",
+ "result": [
+ {
+ "bucket": "4000000000000000",
+ "nodes": [279],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000001",
+ "nodes": [229],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000002",
+ "nodes": [276],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000003",
+ "nodes": [365],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000004",
+ "nodes": [13],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000005",
+ "nodes": [92],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000006",
+ "nodes": [49],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000008",
+ "nodes": [329],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000009",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000a",
+ "nodes": [210],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000b",
+ "nodes": [15],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000c",
+ "nodes": [291],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000d",
+ "nodes": [27],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000e",
+ "nodes": [357],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000f",
+ "nodes": [270],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000010",
+ "nodes": [293],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000011",
+ "nodes": [108],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000012",
+ "nodes": [288],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000013",
+ "nodes": [340],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000000",
+ "nodes": [279],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000001",
+ "nodes": [229],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000002",
+ "nodes": [276],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000003",
+ "nodes": [365],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000004",
+ "nodes": [13],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000005",
+ "nodes": [92],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000006",
+ "nodes": [49],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000008",
+ "nodes": [329],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000009",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000000a",
+ "nodes": [210],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000000b",
+ "nodes": [15],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000000c",
+ "nodes": [291],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000000d",
+ "nodes": [27],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000000e",
+ "nodes": [357],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000000f",
+ "nodes": [270],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000010",
+ "nodes": [293],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000011",
+ "nodes": [108],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000012",
+ "nodes": [288],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000013",
+ "nodes": [340],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000000",
+ "nodes": [279],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000001",
+ "nodes": [229],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000002",
+ "nodes": [276],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000003",
+ "nodes": [365],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000004",
+ "nodes": [13],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000005",
+ "nodes": [92],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000006",
+ "nodes": [49],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000008",
+ "nodes": [329],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000009",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000000a",
+ "nodes": [210],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000000b",
+ "nodes": [15],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000000c",
+ "nodes": [291],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000000d",
+ "nodes": [27],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000000e",
+ "nodes": [357],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000000f",
+ "nodes": [270],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000010",
+ "nodes": [293],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000011",
+ "nodes": [108],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000012",
+ "nodes": [288],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000013",
+ "nodes": [340],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000fe68",
+ "nodes": [253],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000001fe68",
+ "nodes": [253],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000001fe68",
+ "nodes": [253],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c0000000001fe68",
+ "nodes": [253],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "500000000009fe68",
+ "nodes": [253],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "540000000009fe68",
+ "nodes": [253],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "580000000009fe68",
+ "nodes": [253],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c0000000049fe68",
+ "nodes": [253],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "600000000049fe68",
+ "nodes": [253],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "640000000149fe68",
+ "nodes": [253],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "680000000349fe68",
+ "nodes": [253],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c0000000749fe68",
+ "nodes": [253],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "700000000749fe68",
+ "nodes": [253],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "740000001749fe68",
+ "nodes": [253],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "780000003749fe68",
+ "nodes": [253],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c0000003749fe68",
+ "nodes": [253],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "80000000b749fe68",
+ "nodes": [253],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "84000001b749fe68",
+ "nodes": [253],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "88000003b749fe68",
+ "nodes": [253],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8c000007b749fe68",
+ "nodes": [253],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "9000000fb749fe68",
+ "nodes": [253],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "9400001fb749fe68",
+ "nodes": [253],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "9800003fb749fe68",
+ "nodes": [253],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "9c00007fb749fe68",
+ "nodes": [253],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "a000007fb749fe68",
+ "nodes": [253],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "a400007fb749fe68",
+ "nodes": [253],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "a800007fb749fe68",
+ "nodes": [253],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "ac00047fb749fe68",
+ "nodes": [253],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "b000047fb749fe68",
+ "nodes": [253],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "b400147fb749fe68",
+ "nodes": [253],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "b800347fb749fe68",
+ "nodes": [253],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "bc00347fb749fe68",
+ "nodes": [253],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c000b47fb749fe68",
+ "nodes": [253],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c400b47fb749fe68",
+ "nodes": [253],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c800b47fb749fe68",
+ "nodes": [253],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "cc00b47fb749fe68",
+ "nodes": [253],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "d000b47fb749fe68",
+ "nodes": [253],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "d400b47fb749fe68",
+ "nodes": [253],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "d800b47fb749fe68",
+ "nodes": [253],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "dc00b47fb749fe68",
+ "nodes": [253],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "e000b47fb749fe68",
+ "nodes": [253],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "e400b47fb749fe68",
+ "nodes": [253],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000098d2",
+ "nodes": [84],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "44000000000098d2",
+ "nodes": [84],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "48000000000298d2",
+ "nodes": [84],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c000000000698d2",
+ "nodes": [84],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "50000000000e98d2",
+ "nodes": [84],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "54000000000e98d2",
+ "nodes": [84],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "58000000002e98d2",
+ "nodes": [84],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c000000002e98d2",
+ "nodes": [84],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "60000000002e98d2",
+ "nodes": [84],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "64000000012e98d2",
+ "nodes": [84],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "68000000012e98d2",
+ "nodes": [84],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c000000052e98d2",
+ "nodes": [84],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "70000000052e98d2",
+ "nodes": [84],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "74000000152e98d2",
+ "nodes": [84],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "78000000152e98d2",
+ "nodes": [84],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c000000152e98d2",
+ "nodes": [84],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "80000000952e98d2",
+ "nodes": [84],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "84000001952e98d2",
+ "nodes": [84],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "88000001952e98d2",
+ "nodes": [84],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8c000001952e98d2",
+ "nodes": [84],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "90000001952e98d2",
+ "nodes": [84],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "94000001952e98d2",
+ "nodes": [84],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "98000001952e98d2",
+ "nodes": [84],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "9c000041952e98d2",
+ "nodes": [84],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "a00000c1952e98d2",
+ "nodes": [84],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "a40000c1952e98d2",
+ "nodes": [84],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "a80002c1952e98d2",
+ "nodes": [84],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "ac0002c1952e98d2",
+ "nodes": [84],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "b00002c1952e98d2",
+ "nodes": [84],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "b40012c1952e98d2",
+ "nodes": [84],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "b80012c1952e98d2",
+ "nodes": [84],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "bc0012c1952e98d2",
+ "nodes": [84],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00092c1952e98d2",
+ "nodes": [84],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c40192c1952e98d2",
+ "nodes": [84],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c80192c1952e98d2",
+ "nodes": [84],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "cc0192c1952e98d2",
+ "nodes": [84],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "d00992c1952e98d2",
+ "nodes": [84],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "d41992c1952e98d2",
+ "nodes": [84],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "d83992c1952e98d2",
+ "nodes": [84],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "dc7992c1952e98d2",
+ "nodes": [84],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "e07992c1952e98d2",
+ "nodes": [84],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "e47992c1952e98d2",
+ "nodes": [84],
+ "failure": "NONE"
+ }
+ ]
+} \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/hierarchical-grouping-distributor-notakeover.java.results b/vdslib/src/tests/distribution/testdata/hierarchical-grouping-distributor-notakeover.java.results
new file mode 100644
index 00000000000..69d71c83188
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/hierarchical-grouping-distributor-notakeover.java.results
@@ -0,0 +1,730 @@
+{
+ "cluster-state": "distributor:2 storage:9",
+ "distribution": "redundancy 6\ninitial_redundancy 0\nensure_primary_persisted true\nready_copies 0\nactive_per_leaf_group false\ndistributor_auto_ownership_transfer_on_whole_group_down false\ngroup[0].index \"invalid\"\ngroup[0].name \"invalid\"\ngroup[0].capacity 1.0\ngroup[0].partitions \"1|2|*\"\ngroup[1].index \"0\"\ngroup[1].name \"top.0\"\ngroup[1].capacity 1.0\ngroup[1].partitions \"\"\ngroup[1].nodes[0].index 8\ngroup[1].nodes[0].retired false\ngroup[1].nodes[1].index 1\ngroup[1].nodes[1].retired false\ngroup[1].nodes[2].index 6\ngroup[1].nodes[2].retired false\ngroup[2].index \"1\"\ngroup[2].name \"top.1\"\ngroup[2].capacity 1.0\ngroup[2].partitions \"\"\ngroup[2].nodes[0].index 5\ngroup[2].nodes[0].retired false\ngroup[2].nodes[1].index 0\ngroup[2].nodes[1].retired false\ngroup[2].nodes[2].index 2\ngroup[2].nodes[2].retired false\ngroup[3].index \"2\"\ngroup[3].name \"top.2\"\ngroup[3].capacity 1.0\ngroup[3].partitions \"\"\ngroup[3].nodes[0].index 4\ngroup[3].nodes[0].retired false\ngroup[3].nodes[1].index 3\ngroup[3].nodes[1].retired false\ngroup[3].nodes[2].index 7\ngroup[3].nodes[2].retired false\ndisk_distribution MODULO_BID",
+ "node-type": "distributor",
+ "redundancy": 3,
+ "node-count": 10,
+ "up-states": "uim",
+ "result": [
+ {
+ "bucket": "4000000000000000",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000001",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000002",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000003",
+ "nodes": [],
+ "failure": "NO_DISTRIBUTORS_AVAILABLE"
+ },
+ {
+ "bucket": "4000000000000004",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000005",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000006",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000007",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000008",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000009",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000a",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000b",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000c",
+ "nodes": [],
+ "failure": "NO_DISTRIBUTORS_AVAILABLE"
+ },
+ {
+ "bucket": "400000000000000d",
+ "nodes": [],
+ "failure": "NO_DISTRIBUTORS_AVAILABLE"
+ },
+ {
+ "bucket": "400000000000000e",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000f",
+ "nodes": [],
+ "failure": "NO_DISTRIBUTORS_AVAILABLE"
+ },
+ {
+ "bucket": "4000000000000010",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000011",
+ "nodes": [],
+ "failure": "NO_DISTRIBUTORS_AVAILABLE"
+ },
+ {
+ "bucket": "4000000000000012",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000000",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000001",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000002",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000003",
+ "nodes": [],
+ "failure": "NO_DISTRIBUTORS_AVAILABLE"
+ },
+ {
+ "bucket": "4400000000000004",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000005",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000006",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000007",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000008",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000009",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000000a",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000000b",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000000c",
+ "nodes": [],
+ "failure": "NO_DISTRIBUTORS_AVAILABLE"
+ },
+ {
+ "bucket": "440000000000000d",
+ "nodes": [],
+ "failure": "NO_DISTRIBUTORS_AVAILABLE"
+ },
+ {
+ "bucket": "440000000000000e",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000000f",
+ "nodes": [],
+ "failure": "NO_DISTRIBUTORS_AVAILABLE"
+ },
+ {
+ "bucket": "4400000000000010",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000011",
+ "nodes": [],
+ "failure": "NO_DISTRIBUTORS_AVAILABLE"
+ },
+ {
+ "bucket": "4400000000000012",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000000",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000001",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000002",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000003",
+ "nodes": [],
+ "failure": "NO_DISTRIBUTORS_AVAILABLE"
+ },
+ {
+ "bucket": "4800000000000004",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000005",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000006",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000007",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000008",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000009",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000000a",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000000b",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000000c",
+ "nodes": [],
+ "failure": "NO_DISTRIBUTORS_AVAILABLE"
+ },
+ {
+ "bucket": "480000000000000d",
+ "nodes": [],
+ "failure": "NO_DISTRIBUTORS_AVAILABLE"
+ },
+ {
+ "bucket": "480000000000000e",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000000f",
+ "nodes": [],
+ "failure": "NO_DISTRIBUTORS_AVAILABLE"
+ },
+ {
+ "bucket": "4800000000000010",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000011",
+ "nodes": [],
+ "failure": "NO_DISTRIBUTORS_AVAILABLE"
+ },
+ {
+ "bucket": "4800000000000012",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000001fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000001fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c0000000001fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "500000000009fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "540000000009fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "580000000009fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c0000000049fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "600000000049fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "640000000149fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "680000000349fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c0000000749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "700000000749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "740000001749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "780000003749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c0000003749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "80000000b749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "84000001b749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "88000003b749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8c000007b749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "9000000fb749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "9400001fb749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "9800003fb749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "9c00007fb749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "a000007fb749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "a400007fb749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "a800007fb749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "ac00047fb749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "b000047fb749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "b400147fb749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "b800347fb749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "bc00347fb749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c000b47fb749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c400b47fb749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c800b47fb749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "cc00b47fb749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "d000b47fb749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "d400b47fb749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "d800b47fb749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "dc00b47fb749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "e000b47fb749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "e400b47fb749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000098d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "44000000000098d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "48000000000298d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c000000000698d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "50000000000e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "54000000000e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "58000000002e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c000000002e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "60000000002e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "64000000012e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "68000000012e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c000000052e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "70000000052e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "74000000152e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "78000000152e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c000000152e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "80000000952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "84000001952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "88000001952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8c000001952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "90000001952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "94000001952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "98000001952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "9c000041952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "a00000c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "a40000c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "a80002c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "ac0002c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "b00002c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "b40012c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "b80012c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "bc0012c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00092c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c40192c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c80192c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "cc0192c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "d00992c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "d41992c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "d83992c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "dc7992c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "e07992c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "e47992c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ }
+ ]
+} \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/hierarchical-grouping-distributor-takeover.java.results b/vdslib/src/tests/distribution/testdata/hierarchical-grouping-distributor-takeover.java.results
new file mode 100644
index 00000000000..4741a8e06fc
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/hierarchical-grouping-distributor-takeover.java.results
@@ -0,0 +1,730 @@
+{
+ "cluster-state": "distributor:2 storage:9",
+ "distribution": "redundancy 6\ninitial_redundancy 0\nensure_primary_persisted true\nready_copies 0\nactive_per_leaf_group false\ndistributor_auto_ownership_transfer_on_whole_group_down true\ngroup[0].index \"invalid\"\ngroup[0].name \"invalid\"\ngroup[0].capacity 1.0\ngroup[0].partitions \"1|2|*\"\ngroup[1].index \"0\"\ngroup[1].name \"top.0\"\ngroup[1].capacity 1.0\ngroup[1].partitions \"\"\ngroup[1].nodes[0].index 8\ngroup[1].nodes[0].retired false\ngroup[1].nodes[1].index 1\ngroup[1].nodes[1].retired false\ngroup[1].nodes[2].index 6\ngroup[1].nodes[2].retired false\ngroup[2].index \"1\"\ngroup[2].name \"top.1\"\ngroup[2].capacity 1.0\ngroup[2].partitions \"\"\ngroup[2].nodes[0].index 5\ngroup[2].nodes[0].retired false\ngroup[2].nodes[1].index 0\ngroup[2].nodes[1].retired false\ngroup[2].nodes[2].index 2\ngroup[2].nodes[2].retired false\ngroup[3].index \"2\"\ngroup[3].name \"top.2\"\ngroup[3].capacity 1.0\ngroup[3].partitions \"\"\ngroup[3].nodes[0].index 4\ngroup[3].nodes[0].retired false\ngroup[3].nodes[1].index 3\ngroup[3].nodes[1].retired false\ngroup[3].nodes[2].index 7\ngroup[3].nodes[2].retired false\ndisk_distribution MODULO_BID",
+ "node-type": "distributor",
+ "redundancy": 3,
+ "node-count": 10,
+ "up-states": "uim",
+ "result": [
+ {
+ "bucket": "4000000000000000",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000001",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000002",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000003",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000004",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000005",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000006",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000007",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000008",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000009",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000a",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000b",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000c",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000d",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000e",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000f",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000010",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000011",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000012",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000000",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000001",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000002",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000003",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000004",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000005",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000006",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000007",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000008",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000009",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000000a",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000000b",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000000c",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000000d",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000000e",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000000f",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000010",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000011",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000012",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000000",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000001",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000002",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000003",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000004",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000005",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000006",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000007",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000008",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000009",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000000a",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000000b",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000000c",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000000d",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000000e",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000000f",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000010",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000011",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000012",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000001fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000001fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c0000000001fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "500000000009fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "540000000009fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "580000000009fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c0000000049fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "600000000049fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "640000000149fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "680000000349fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c0000000749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "700000000749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "740000001749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "780000003749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c0000003749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "80000000b749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "84000001b749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "88000003b749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8c000007b749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "9000000fb749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "9400001fb749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "9800003fb749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "9c00007fb749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "a000007fb749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "a400007fb749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "a800007fb749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "ac00047fb749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "b000047fb749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "b400147fb749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "b800347fb749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "bc00347fb749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c000b47fb749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c400b47fb749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c800b47fb749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "cc00b47fb749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "d000b47fb749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "d400b47fb749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "d800b47fb749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "dc00b47fb749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "e000b47fb749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "e400b47fb749fe68",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000098d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "44000000000098d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "48000000000298d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c000000000698d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "50000000000e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "54000000000e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "58000000002e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c000000002e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "60000000002e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "64000000012e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "68000000012e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c000000052e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "70000000052e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "74000000152e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "78000000152e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c000000152e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "80000000952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "84000001952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "88000001952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8c000001952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "90000001952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "94000001952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "98000001952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "9c000041952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "a00000c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "a40000c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "a80002c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "ac0002c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "b00002c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "b40012c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "b80012c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "bc0012c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00092c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c40192c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c80192c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "cc0192c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "d00992c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "d41992c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "d83992c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "dc7992c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "e07992c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "e47992c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ }
+ ]
+} \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/hierarchical-grouping.java.results b/vdslib/src/tests/distribution/testdata/hierarchical-grouping.java.results
new file mode 100644
index 00000000000..125f73c512d
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/hierarchical-grouping.java.results
@@ -0,0 +1,730 @@
+{
+ "cluster-state": "distributor:10",
+ "distribution": "redundancy 6\ninitial_redundancy 0\nensure_primary_persisted true\nready_copies 0\nactive_per_leaf_group false\ndistributor_auto_ownership_transfer_on_whole_group_down true\ngroup[0].index \"invalid\"\ngroup[0].name \"invalid\"\ngroup[0].capacity 1.0\ngroup[0].partitions \"1|2|*\"\ngroup[1].index \"0\"\ngroup[1].name \"top.0\"\ngroup[1].capacity 1.0\ngroup[1].partitions \"\"\ngroup[1].nodes[0].index 8\ngroup[1].nodes[0].retired false\ngroup[1].nodes[1].index 1\ngroup[1].nodes[1].retired false\ngroup[1].nodes[2].index 6\ngroup[1].nodes[2].retired false\ngroup[2].index \"1\"\ngroup[2].name \"top.1\"\ngroup[2].capacity 1.0\ngroup[2].partitions \"\"\ngroup[2].nodes[0].index 5\ngroup[2].nodes[0].retired false\ngroup[2].nodes[1].index 0\ngroup[2].nodes[1].retired false\ngroup[2].nodes[2].index 2\ngroup[2].nodes[2].retired false\ngroup[3].index \"2\"\ngroup[3].name \"top.2\"\ngroup[3].capacity 1.0\ngroup[3].partitions \"\"\ngroup[3].nodes[0].index 4\ngroup[3].nodes[0].retired false\ngroup[3].nodes[1].index 3\ngroup[3].nodes[1].retired false\ngroup[3].nodes[2].index 7\ngroup[3].nodes[2].retired false\ndisk_distribution MODULO_BID",
+ "node-type": "distributor",
+ "redundancy": 3,
+ "node-count": 10,
+ "up-states": "uim",
+ "result": [
+ {
+ "bucket": "4000000000000000",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000001",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000002",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000003",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000004",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000005",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000008",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000009",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000a",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000b",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000c",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000d",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000f",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000010",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000011",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000012",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000000",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000001",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000002",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000003",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000004",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000005",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000008",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000009",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000000a",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000000b",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000000c",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000000d",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000000e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000000f",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000010",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000011",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000012",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000000",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000001",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000002",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000003",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000004",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000005",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000008",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000009",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000000a",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000000b",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000000c",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000000d",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000000e",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000000f",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000010",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000011",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000012",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000fe68",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000001fe68",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000001fe68",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c0000000001fe68",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "500000000009fe68",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "540000000009fe68",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "580000000009fe68",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c0000000049fe68",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "600000000049fe68",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "640000000149fe68",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "680000000349fe68",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c0000000749fe68",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "700000000749fe68",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "740000001749fe68",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "780000003749fe68",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c0000003749fe68",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "80000000b749fe68",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "84000001b749fe68",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "88000003b749fe68",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8c000007b749fe68",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "9000000fb749fe68",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "9400001fb749fe68",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "9800003fb749fe68",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "9c00007fb749fe68",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "a000007fb749fe68",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "a400007fb749fe68",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "a800007fb749fe68",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "ac00047fb749fe68",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "b000047fb749fe68",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "b400147fb749fe68",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "b800347fb749fe68",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "bc00347fb749fe68",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c000b47fb749fe68",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c400b47fb749fe68",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c800b47fb749fe68",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "cc00b47fb749fe68",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "d000b47fb749fe68",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "d400b47fb749fe68",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "d800b47fb749fe68",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "dc00b47fb749fe68",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "e000b47fb749fe68",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "e400b47fb749fe68",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000098d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "44000000000098d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "48000000000298d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c000000000698d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "50000000000e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "54000000000e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "58000000002e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c000000002e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "60000000002e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "64000000012e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "68000000012e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c000000052e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "70000000052e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "74000000152e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "78000000152e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c000000152e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "80000000952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "84000001952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "88000001952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8c000001952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "90000001952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "94000001952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "98000001952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "9c000041952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "a00000c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "a40000c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "a80002c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "ac0002c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "b00002c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "b40012c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "b80012c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "bc0012c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00092c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c40192c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c80192c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "cc0192c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "d00992c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "d41992c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "d83992c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "dc7992c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "e07992c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "e47992c1952e98d2",
+ "nodes": [1],
+ "failure": "NONE"
+ }
+ ]
+} \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/java_capacity.cfg b/vdslib/src/tests/distribution/testdata/java_capacity.cfg
new file mode 100644
index 00000000000..fc0e597013d
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/java_capacity.cfg
@@ -0,0 +1,46 @@
+redundancy 5
+group[7]
+group[0].partitions "*|*"
+group[0].index "invalid"
+group[0].name "invalid"
+group[0].nodes[0]
+group[1].partitions "1|*"
+group[1].index "0"
+group[1].name "switch0"
+group[1].nodes[0]
+group[2].partitions ""
+group[2].index "0.0"
+group[2].name "rack0"
+group[2].nodes[4]
+group[2].nodes[0].index 0
+group[2].nodes[1].index 1
+group[2].nodes[2].index 2
+group[2].nodes[3].index 3
+group[3].partitions ""
+group[3].index "0.1"
+group[3].name "rack1"
+group[3].nodes[4]
+group[3].nodes[0].index 8
+group[3].nodes[1].index 9
+group[3].nodes[2].index 14
+group[3].nodes[3].index 15
+group[4].partitions "*"
+group[4].index "1"
+group[4].name "switch1"
+group[4].nodes[0]
+group[5].partitions ""
+group[5].index "1.0"
+group[5].name "rack0"
+group[5].nodes[4]
+group[5].nodes[0].index 4
+group[5].nodes[1].index 5
+group[5].nodes[2].index 6
+group[5].nodes[3].index 17
+group[6].partitions ""
+group[6].index "1.1"
+group[6].name "rack1"
+group[6].nodes[4]
+group[6].nodes[0].index 10
+group[6].nodes[1].index 12
+group[6].nodes[2].index 13
+group[6].nodes[3].index 7 \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/java_capacity.distribution b/vdslib/src/tests/distribution/testdata/java_capacity.distribution
new file mode 100644
index 00000000000..1087c796fd7
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/java_capacity.distribution
@@ -0,0 +1,8955 @@
+0 0 1 6
+0 0 2 6
+0 0 3 6
+0 0 4 6
+0 0 5 6
+1 0 1 6
+1 0 2 6
+1 0 3 6
+1 0 4 6
+1 0 5 6
+1 1 1 8
+1 1 2 8
+1 1 3 8
+1 1 4 8
+1 1 5 8
+2 0 1 6
+2 0 2 6
+2 0 3 6
+2 0 4 6
+2 0 5 6
+2 1 1 8
+2 1 2 8
+2 1 3 8
+2 1 4 8
+2 1 5 8
+2 2 1 2
+2 2 2 2
+2 2 3 2
+2 2 4 2
+2 2 5 2
+2 3 1 5
+2 3 2 5
+2 3 3 5
+2 3 4 5
+2 3 5 5
+3 0 1 6
+3 0 2 6
+3 0 3 6
+3 0 4 6
+3 0 5 6
+3 1 1 8
+3 1 2 8
+3 1 3 8
+3 1 4 8
+3 1 5 8
+3 2 1 2
+3 2 2 2
+3 2 3 2
+3 2 4 2
+3 2 5 2
+3 3 1 5
+3 3 2 5
+3 3 3 5
+3 3 4 5
+3 3 5 5
+3 4 1 12
+3 4 2 12
+3 4 3 12
+3 4 4 12
+3 4 5 12
+3 5 1 6
+3 5 2 6
+3 5 3 6
+3 5 4 6
+3 5 5 6
+3 6 1 8
+3 6 2 8
+3 6 3 8
+3 6 4 8
+3 6 5 8
+3 7 1 2
+3 7 2 2
+3 7 3 2
+3 7 4 2
+3 7 5 2
+4 0 1 6
+4 0 2 6
+4 0 3 6
+4 0 4 6
+4 0 5 6
+4 1 1 8
+4 1 2 8
+4 1 3 8
+4 1 4 8
+4 1 5 8
+4 2 1 2
+4 2 2 2
+4 2 3 2
+4 2 4 2
+4 2 5 2
+4 3 1 5
+4 3 2 5
+4 3 3 5
+4 3 4 5
+4 3 5 5
+4 4 1 12
+4 4 2 12
+4 4 3 12
+4 4 4 12
+4 4 5 12
+4 5 1 6
+4 5 2 6
+4 5 3 6
+4 5 4 6
+4 5 5 6
+4 6 1 8
+4 6 2 8
+4 6 3 8
+4 6 4 8
+4 6 5 8
+4 7 1 2
+4 7 2 2
+4 7 3 2
+4 7 4 2
+4 7 5 2
+4 8 1 8
+4 8 2 8
+4 8 3 8
+4 8 4 8
+4 8 5 8
+4 9 1 5
+4 9 2 5
+4 9 3 5
+4 9 4 5
+4 9 5 5
+4 10 1 13
+4 10 2 13
+4 10 3 13
+4 10 4 13
+4 10 5 13
+4 11 1 6
+4 11 2 6
+4 11 3 6
+4 11 4 6
+4 11 5 6
+4 12 1 6
+4 12 2 6
+4 12 3 6
+4 12 4 6
+4 12 5 6
+4 13 1 8
+4 13 2 8
+4 13 3 8
+4 13 4 8
+4 13 5 8
+4 14 1 0
+4 14 2 0
+4 14 3 0
+4 14 4 0
+4 14 5 0
+4 15 1 5
+4 15 2 5
+4 15 3 5
+4 15 4 5
+4 15 5 5
+5 0 1 6
+5 0 2 6
+5 0 3 6
+5 0 4 6
+5 0 5 6
+5 1 1 8
+5 1 2 8
+5 1 3 8
+5 1 4 8
+5 1 5 8
+5 2 1 2
+5 2 2 2
+5 2 3 2
+5 2 4 2
+5 2 5 2
+5 3 1 5
+5 3 2 5
+5 3 3 5
+5 3 4 5
+5 3 5 5
+5 4 1 12
+5 4 2 12
+5 4 3 12
+5 4 4 12
+5 4 5 12
+5 5 1 6
+5 5 2 6
+5 5 3 6
+5 5 4 6
+5 5 5 6
+5 6 1 8
+5 6 2 8
+5 6 3 8
+5 6 4 8
+5 6 5 8
+5 7 1 2
+5 7 2 2
+5 7 3 2
+5 7 4 2
+5 7 5 2
+5 8 1 8
+5 8 2 8
+5 8 3 8
+5 8 4 8
+5 8 5 8
+5 9 1 5
+5 9 2 5
+5 9 3 5
+5 9 4 5
+5 9 5 5
+5 10 1 13
+5 10 2 13
+5 10 3 13
+5 10 4 13
+5 10 5 13
+5 11 1 6
+5 11 2 6
+5 11 3 6
+5 11 4 6
+5 11 5 6
+5 12 1 6
+5 12 2 6
+5 12 3 6
+5 12 4 6
+5 12 5 6
+5 13 1 8
+5 13 2 8
+5 13 3 8
+5 13 4 8
+5 13 5 8
+5 14 1 0
+5 14 2 0
+5 14 3 0
+5 14 4 0
+5 14 5 0
+5 15 1 5
+5 15 2 5
+5 15 3 5
+5 15 4 5
+5 15 5 5
+5 16 1 7
+5 16 2 7
+5 16 3 7
+5 16 4 7
+5 16 5 7
+5 17 1 7
+5 17 2 7
+5 17 3 7
+5 17 4 7
+5 17 5 7
+5 18 1 17
+5 18 2 17
+5 18 3 17
+5 18 4 17
+5 18 5 17
+5 19 1 1
+5 19 2 1
+5 19 3 1
+5 19 4 1
+5 19 5 1
+5 20 1 8
+5 20 2 8
+5 20 3 8
+5 20 4 8
+5 20 5 8
+5 21 1 4
+5 21 2 4
+5 21 3 4
+5 21 4 4
+5 21 5 4
+5 22 1 4
+5 22 2 4
+5 22 3 4
+5 22 4 4
+5 22 5 4
+5 23 1 5
+5 23 2 5
+5 23 3 5
+5 23 4 5
+5 23 5 5
+5 24 1 0
+5 24 2 0
+5 24 3 0
+5 24 4 0
+5 24 5 0
+5 25 1 17
+5 25 2 17
+5 25 3 17
+5 25 4 17
+5 25 5 17
+5 26 1 8
+5 26 2 8
+5 26 3 8
+5 26 4 8
+5 26 5 8
+5 27 1 12
+5 27 2 12
+5 27 3 12
+5 27 4 12
+5 27 5 12
+5 28 1 7
+5 28 2 7
+5 28 3 7
+5 28 4 7
+5 28 5 7
+5 29 1 1
+5 29 2 1
+5 29 3 1
+5 29 4 1
+5 29 5 1
+5 30 1 10
+5 30 2 10
+5 30 3 10
+5 30 4 10
+5 30 5 10
+5 31 1 8
+5 31 2 8
+5 31 3 8
+5 31 4 8
+5 31 5 8
+6 0 1 6
+6 0 2 6
+6 0 3 6
+6 0 4 6
+6 0 5 6
+6 1 1 8
+6 1 2 8
+6 1 3 8
+6 1 4 8
+6 1 5 8
+6 2 1 2
+6 2 2 2
+6 2 3 2
+6 2 4 2
+6 2 5 2
+6 3 1 5
+6 3 2 5
+6 3 3 5
+6 3 4 5
+6 3 5 5
+6 4 1 12
+6 4 2 12
+6 4 3 12
+6 4 4 12
+6 4 5 12
+6 5 1 6
+6 5 2 6
+6 5 3 6
+6 5 4 6
+6 5 5 6
+6 6 1 8
+6 6 2 8
+6 6 3 8
+6 6 4 8
+6 6 5 8
+6 7 1 2
+6 7 2 2
+6 7 3 2
+6 7 4 2
+6 7 5 2
+6 8 1 8
+6 8 2 8
+6 8 3 8
+6 8 4 8
+6 8 5 8
+6 9 1 5
+6 9 2 5
+6 9 3 5
+6 9 4 5
+6 9 5 5
+6 10 1 13
+6 10 2 13
+6 10 3 13
+6 10 4 13
+6 10 5 13
+6 11 1 6
+6 11 2 6
+6 11 3 6
+6 11 4 6
+6 11 5 6
+6 12 1 6
+6 12 2 6
+6 12 3 6
+6 12 4 6
+6 12 5 6
+6 13 1 8
+6 13 2 8
+6 13 3 8
+6 13 4 8
+6 13 5 8
+6 14 1 0
+6 14 2 0
+6 14 3 0
+6 14 4 0
+6 14 5 0
+6 15 1 5
+6 15 2 5
+6 15 3 5
+6 15 4 5
+6 15 5 5
+6 16 1 7
+6 16 2 7
+6 16 3 7
+6 16 4 7
+6 16 5 7
+6 17 1 7
+6 17 2 7
+6 17 3 7
+6 17 4 7
+6 17 5 7
+6 18 1 17
+6 18 2 17
+6 18 3 17
+6 18 4 17
+6 18 5 17
+6 19 1 1
+6 19 2 1
+6 19 3 1
+6 19 4 1
+6 19 5 1
+6 20 1 8
+6 20 2 8
+6 20 3 8
+6 20 4 8
+6 20 5 8
+6 21 1 4
+6 21 2 4
+6 21 3 4
+6 21 4 4
+6 21 5 4
+6 22 1 4
+6 22 2 4
+6 22 3 4
+6 22 4 4
+6 22 5 4
+6 23 1 5
+6 23 2 5
+6 23 3 5
+6 23 4 5
+6 23 5 5
+6 24 1 0
+6 24 2 0
+6 24 3 0
+6 24 4 0
+6 24 5 0
+6 25 1 17
+6 25 2 17
+6 25 3 17
+6 25 4 17
+6 25 5 17
+6 26 1 8
+6 26 2 8
+6 26 3 8
+6 26 4 8
+6 26 5 8
+6 27 1 12
+6 27 2 12
+6 27 3 12
+6 27 4 12
+6 27 5 12
+6 28 1 7
+6 28 2 7
+6 28 3 7
+6 28 4 7
+6 28 5 7
+6 29 1 1
+6 29 2 1
+6 29 3 1
+6 29 4 1
+6 29 5 1
+6 30 1 10
+6 30 2 10
+6 30 3 10
+6 30 4 10
+6 30 5 10
+6 31 1 8
+6 31 2 8
+6 31 3 8
+6 31 4 8
+6 31 5 8
+6 32 1 5
+6 32 2 5
+6 32 3 5
+6 32 4 5
+6 32 5 5
+6 33 1 12
+6 33 2 12
+6 33 3 12
+6 33 4 12
+6 33 5 12
+6 34 1 1
+6 34 2 1
+6 34 3 1
+6 34 4 1
+6 34 5 1
+6 35 1 7
+6 35 2 7
+6 35 3 7
+6 35 4 7
+6 35 5 7
+6 36 1 3
+6 36 2 3
+6 36 3 3
+6 36 4 3
+6 36 5 3
+6 37 1 5
+6 37 2 5
+6 37 3 5
+6 37 4 5
+6 37 5 5
+6 38 1 3
+6 38 2 3
+6 38 3 3
+6 38 4 3
+6 38 5 3
+6 39 1 4
+6 39 2 4
+6 39 3 4
+6 39 4 4
+6 39 5 4
+6 40 1 5
+6 40 2 5
+6 40 3 5
+6 40 4 5
+6 40 5 5
+6 41 1 3
+6 41 2 3
+6 41 3 3
+6 41 4 3
+6 41 5 3
+6 42 1 4
+6 42 2 4
+6 42 3 4
+6 42 4 4
+6 42 5 4
+6 43 1 1
+6 43 2 1
+6 43 3 1
+6 43 4 1
+6 43 5 1
+6 44 1 8
+6 44 2 8
+6 44 3 8
+6 44 4 8
+6 44 5 8
+6 45 1 10
+6 45 2 10
+6 45 3 10
+6 45 4 10
+6 45 5 10
+6 46 1 5
+6 46 2 5
+6 46 3 5
+6 46 4 5
+6 46 5 5
+6 47 1 7
+6 47 2 7
+6 47 3 7
+6 47 4 7
+6 47 5 7
+6 48 1 0
+6 48 2 0
+6 48 3 0
+6 48 4 0
+6 48 5 0
+6 49 1 8
+6 49 2 8
+6 49 3 8
+6 49 4 8
+6 49 5 8
+6 50 1 9
+6 50 2 9
+6 50 3 9
+6 50 4 9
+6 50 5 9
+6 51 1 7
+6 51 2 7
+6 51 3 7
+6 51 4 7
+6 51 5 7
+6 52 1 13
+6 52 2 13
+6 52 3 13
+6 52 4 13
+6 52 5 13
+6 53 1 10
+6 53 2 10
+6 53 3 10
+6 53 4 10
+6 53 5 10
+6 54 1 1
+6 54 2 1
+6 54 3 1
+6 54 4 1
+6 54 5 1
+6 55 1 8
+6 55 2 8
+6 55 3 8
+6 55 4 8
+6 55 5 8
+6 56 1 8
+6 56 2 8
+6 56 3 8
+6 56 4 8
+6 56 5 8
+6 57 1 6
+6 57 2 6
+6 57 3 6
+6 57 4 6
+6 57 5 6
+6 58 1 6
+6 58 2 6
+6 58 3 6
+6 58 4 6
+6 58 5 6
+6 59 1 1
+6 59 2 1
+6 59 3 1
+6 59 4 1
+6 59 5 1
+6 60 1 6
+6 60 2 6
+6 60 3 6
+6 60 4 6
+6 60 5 6
+6 61 1 3
+6 61 2 3
+6 61 3 3
+6 61 4 3
+6 61 5 3
+6 62 1 10
+6 62 2 10
+6 62 3 10
+6 62 4 10
+6 62 5 10
+6 63 1 13
+6 63 2 13
+6 63 3 13
+6 63 4 13
+6 63 5 13
+7 57 1 6
+7 57 2 6
+7 57 3 6
+7 57 4 6
+7 57 5 6
+7 93 1 12
+7 93 2 12
+7 93 3 12
+7 93 4 12
+7 93 5 12
+7 18 1 17
+7 18 2 17
+7 18 3 17
+7 18 4 17
+7 18 5 17
+7 93 1 12
+7 93 2 12
+7 93 3 12
+7 93 4 12
+7 93 5 12
+7 33 1 12
+7 33 2 12
+7 33 3 12
+7 33 4 12
+7 33 5 12
+7 95 1 2
+7 95 2 2
+7 95 3 2
+7 95 4 2
+7 95 5 2
+7 124 1 0
+7 124 2 0
+7 124 3 0
+7 124 4 0
+7 124 5 0
+7 101 1 3
+7 101 2 3
+7 101 3 3
+7 101 4 3
+7 101 5 3
+7 78 1 7
+7 78 2 7
+7 78 3 7
+7 78 4 7
+7 78 5 7
+7 105 1 14
+7 105 2 14
+7 105 3 14
+7 105 4 14
+7 105 5 14
+7 55 1 8
+7 55 2 8
+7 55 3 8
+7 55 4 8
+7 55 5 8
+7 105 1 14
+7 105 2 14
+7 105 3 14
+7 105 4 14
+7 105 5 14
+7 113 1 8
+7 113 2 8
+7 113 3 8
+7 113 4 8
+7 113 5 8
+7 38 1 3
+7 38 2 3
+7 38 3 3
+7 38 4 3
+7 38 5 3
+7 51 1 7
+7 51 2 7
+7 51 3 7
+7 51 4 7
+7 51 5 7
+7 39 1 4
+7 39 2 4
+7 39 3 4
+7 39 4 4
+7 39 5 4
+7 89 1 14
+7 89 2 14
+7 89 3 14
+7 89 4 14
+7 89 5 14
+7 4 1 12
+7 4 2 12
+7 4 3 12
+7 4 4 12
+7 4 5 12
+7 68 1 6
+7 68 2 6
+7 68 3 6
+7 68 4 6
+7 68 5 6
+7 96 1 4
+7 96 2 4
+7 96 3 4
+7 96 4 4
+7 96 5 4
+7 126 1 10
+7 126 2 10
+7 126 3 10
+7 126 4 10
+7 126 5 10
+7 54 1 1
+7 54 2 1
+7 54 3 1
+7 54 4 1
+7 54 5 1
+7 34 1 1
+7 34 2 1
+7 34 3 1
+7 34 4 1
+7 34 5 1
+7 89 1 14
+7 89 2 14
+7 89 3 14
+7 89 4 14
+7 89 5 14
+7 122 1 2
+7 122 2 2
+7 122 3 2
+7 122 4 2
+7 122 5 2
+7 53 1 10
+7 53 2 10
+7 53 3 10
+7 53 4 10
+7 53 5 10
+7 105 1 14
+7 105 2 14
+7 105 3 14
+7 105 4 14
+7 105 5 14
+7 90 1 2
+7 90 2 2
+7 90 3 2
+7 90 4 2
+7 90 5 2
+7 11 1 6
+7 11 2 6
+7 11 3 6
+7 11 4 6
+7 11 5 6
+7 59 1 1
+7 59 2 1
+7 59 3 1
+7 59 4 1
+7 59 5 1
+7 26 1 8
+7 26 2 8
+7 26 3 8
+7 26 4 8
+7 26 5 8
+7 50 1 9
+7 50 2 9
+7 50 3 9
+7 50 4 9
+7 50 5 9
+7 19 1 1
+7 19 2 1
+7 19 3 1
+7 19 4 1
+7 19 5 1
+7 70 1 0
+7 70 2 0
+7 70 3 0
+7 70 4 0
+7 70 5 0
+7 25 1 17
+7 25 2 17
+7 25 3 17
+7 25 4 17
+7 25 5 17
+7 48 1 0
+7 48 2 0
+7 48 3 0
+7 48 4 0
+7 48 5 0
+7 24 1 0
+7 24 2 0
+7 24 3 0
+7 24 4 0
+7 24 5 0
+7 27 1 12
+7 27 2 12
+7 27 3 12
+7 27 4 12
+7 27 5 12
+7 44 1 8
+7 44 2 8
+7 44 3 8
+7 44 4 8
+7 44 5 8
+7 44 1 8
+7 44 2 8
+7 44 3 8
+7 44 4 8
+7 44 5 8
+7 68 1 6
+7 68 2 6
+7 68 3 6
+7 68 4 6
+7 68 5 6
+7 65 1 1
+7 65 2 1
+7 65 3 1
+7 65 4 1
+7 65 5 1
+7 2 1 2
+7 2 2 2
+7 2 3 2
+7 2 4 2
+7 2 5 2
+7 124 1 0
+7 124 2 0
+7 124 3 0
+7 124 4 0
+7 124 5 0
+7 101 1 3
+7 101 2 3
+7 101 3 3
+7 101 4 3
+7 101 5 3
+7 2 1 2
+7 2 2 2
+7 2 3 2
+7 2 4 2
+7 2 5 2
+7 42 1 4
+7 42 2 4
+7 42 3 4
+7 42 4 4
+7 42 5 4
+7 127 1 2
+7 127 2 2
+7 127 3 2
+7 127 4 2
+7 127 5 2
+7 110 1 3
+7 110 2 3
+7 110 3 3
+7 110 4 3
+7 110 5 3
+7 109 1 17
+7 109 2 17
+7 109 3 17
+7 109 4 17
+7 109 5 17
+7 24 1 0
+7 24 2 0
+7 24 3 0
+7 24 4 0
+7 24 5 0
+7 22 1 4
+7 22 2 4
+7 22 3 4
+7 22 4 4
+7 22 5 4
+7 117 1 0
+7 117 2 0
+7 117 3 0
+7 117 4 0
+7 117 5 0
+7 87 1 0
+7 87 2 0
+7 87 3 0
+7 87 4 0
+7 87 5 0
+7 35 1 7
+7 35 2 7
+7 35 3 7
+7 35 4 7
+7 35 5 7
+7 37 1 5
+7 37 2 5
+7 37 3 5
+7 37 4 5
+7 37 5 5
+7 51 1 7
+7 51 2 7
+7 51 3 7
+7 51 4 7
+7 51 5 7
+7 85 1 9
+7 85 2 9
+7 85 3 9
+7 85 4 9
+7 85 5 9
+7 10 1 13
+7 10 2 13
+7 10 3 13
+7 10 4 13
+7 10 5 13
+7 23 1 5
+7 23 2 5
+7 23 3 5
+7 23 4 5
+7 23 5 5
+7 7 1 2
+7 7 2 2
+7 7 3 2
+7 7 4 2
+7 7 5 2
+7 67 1 5
+7 67 2 5
+7 67 3 5
+7 67 4 5
+7 67 5 5
+7 106 1 1
+7 106 2 1
+7 106 3 1
+7 106 4 1
+7 106 5 1
+7 88 1 5
+7 88 2 5
+7 88 3 5
+7 88 4 5
+7 88 5 5
+8 91 1 13
+8 91 2 13
+8 91 3 13
+8 91 4 13
+8 91 5 13
+8 237 1 6
+8 237 2 6
+8 237 3 6
+8 237 4 6
+8 237 5 6
+8 214 1 17
+8 214 2 17
+8 214 3 17
+8 214 4 17
+8 214 5 17
+8 65 1 1
+8 65 2 1
+8 65 3 1
+8 65 4 1
+8 65 5 1
+8 132 1 13
+8 132 2 13
+8 132 3 13
+8 132 4 13
+8 132 5 13
+8 211 1 3
+8 211 2 3
+8 211 3 3
+8 211 4 3
+8 211 5 3
+8 184 1 17
+8 184 2 17
+8 184 3 17
+8 184 4 17
+8 184 5 17
+8 171 1 6
+8 171 2 6
+8 171 3 6
+8 171 4 6
+8 171 5 6
+8 63 1 13
+8 63 2 13
+8 63 3 13
+8 63 4 13
+8 63 5 13
+8 179 1 10
+8 179 2 10
+8 179 3 10
+8 179 4 10
+8 179 5 10
+8 249 1 5
+8 249 2 5
+8 249 3 5
+8 249 4 5
+8 249 5 5
+8 102 1 6
+8 102 2 6
+8 102 3 6
+8 102 4 6
+8 102 5 6
+8 170 1 14
+8 170 2 14
+8 170 3 14
+8 170 4 14
+8 170 5 14
+8 199 1 6
+8 199 2 6
+8 199 3 6
+8 199 4 6
+8 199 5 6
+8 18 1 17
+8 18 2 17
+8 18 3 17
+8 18 4 17
+8 18 5 17
+8 147 1 4
+8 147 2 4
+8 147 3 4
+8 147 4 4
+8 147 5 4
+8 58 1 6
+8 58 2 6
+8 58 3 6
+8 58 4 6
+8 58 5 6
+8 185 1 14
+8 185 2 14
+8 185 3 14
+8 185 4 14
+8 185 5 14
+8 16 1 7
+8 16 2 7
+8 16 3 7
+8 16 4 7
+8 16 5 7
+8 9 1 5
+8 9 2 5
+8 9 3 5
+8 9 4 5
+8 9 5 5
+8 54 1 1
+8 54 2 1
+8 54 3 1
+8 54 4 1
+8 54 5 1
+8 44 1 8
+8 44 2 8
+8 44 3 8
+8 44 4 8
+8 44 5 8
+8 22 1 4
+8 22 2 4
+8 22 3 4
+8 22 4 4
+8 22 5 4
+8 212 1 17
+8 212 2 17
+8 212 3 17
+8 212 4 17
+8 212 5 17
+8 57 1 6
+8 57 2 6
+8 57 3 6
+8 57 4 6
+8 57 5 6
+8 51 1 7
+8 51 2 7
+8 51 3 7
+8 51 4 7
+8 51 5 7
+8 217 1 12
+8 217 2 12
+8 217 3 12
+8 217 4 12
+8 217 5 12
+8 176 1 2
+8 176 2 2
+8 176 3 2
+8 176 4 2
+8 176 5 2
+8 180 1 14
+8 180 2 14
+8 180 3 14
+8 180 4 14
+8 180 5 14
+8 216 1 4
+8 216 2 4
+8 216 3 4
+8 216 4 4
+8 216 5 4
+8 34 1 1
+8 34 2 1
+8 34 3 1
+8 34 4 1
+8 34 5 1
+8 146 1 5
+8 146 2 5
+8 146 3 5
+8 146 4 5
+8 146 5 5
+8 105 1 14
+8 105 2 14
+8 105 3 14
+8 105 4 14
+8 105 5 14
+8 151 1 12
+8 151 2 12
+8 151 3 12
+8 151 4 12
+8 151 5 12
+8 80 1 0
+8 80 2 0
+8 80 3 0
+8 80 4 0
+8 80 5 0
+8 32 1 5
+8 32 2 5
+8 32 3 5
+8 32 4 5
+8 32 5 5
+8 241 1 1
+8 241 2 1
+8 241 3 1
+8 241 4 1
+8 241 5 1
+8 224 1 7
+8 224 2 7
+8 224 3 7
+8 224 4 7
+8 224 5 7
+8 211 1 3
+8 211 2 3
+8 211 3 3
+8 211 4 3
+8 211 5 3
+8 52 1 13
+8 52 2 13
+8 52 3 13
+8 52 4 13
+8 52 5 13
+8 56 1 8
+8 56 2 8
+8 56 3 8
+8 56 4 8
+8 56 5 8
+8 152 1 9
+8 152 2 9
+8 152 3 9
+8 152 4 9
+8 152 5 9
+8 178 1 0
+8 178 2 0
+8 178 3 0
+8 178 4 0
+8 178 5 0
+8 93 1 12
+8 93 2 12
+8 93 3 12
+8 93 4 12
+8 93 5 12
+8 251 1 2
+8 251 2 2
+8 251 3 2
+8 251 4 2
+8 251 5 2
+8 152 1 9
+8 152 2 9
+8 152 3 9
+8 152 4 9
+8 152 5 9
+8 6 1 8
+8 6 2 8
+8 6 3 8
+8 6 4 8
+8 6 5 8
+8 93 1 12
+8 93 2 12
+8 93 3 12
+8 93 4 12
+8 93 5 12
+8 81 1 10
+8 81 2 10
+8 81 3 10
+8 81 4 10
+8 81 5 10
+8 45 1 10
+8 45 2 10
+8 45 3 10
+8 45 4 10
+8 45 5 10
+8 125 1 14
+8 125 2 14
+8 125 3 14
+8 125 4 14
+8 125 5 14
+8 172 1 4
+8 172 2 4
+8 172 3 4
+8 172 4 4
+8 172 5 4
+8 31 1 8
+8 31 2 8
+8 31 3 8
+8 31 4 8
+8 31 5 8
+8 150 1 9
+8 150 2 9
+8 150 3 9
+8 150 4 9
+8 150 5 9
+8 216 1 4
+8 216 2 4
+8 216 3 4
+8 216 4 4
+8 216 5 4
+8 243 1 15
+8 243 2 15
+8 243 3 15
+8 243 4 15
+8 243 5 15
+8 162 1 14
+8 162 2 14
+8 162 3 14
+8 162 4 14
+8 162 5 14
+8 138 1 14
+8 138 2 14
+8 138 3 14
+8 138 4 14
+8 138 5 14
+8 109 1 17
+8 109 2 17
+8 109 3 17
+8 109 4 17
+8 109 5 17
+8 146 1 5
+8 146 2 5
+8 146 3 5
+8 146 4 5
+8 146 5 5
+8 234 1 4
+8 234 2 4
+8 234 3 4
+8 234 4 4
+8 234 5 4
+8 175 1 15
+8 175 2 15
+8 175 3 15
+8 175 4 15
+8 175 5 15
+8 165 1 5
+8 165 2 5
+8 165 3 5
+8 165 4 5
+8 165 5 5
+8 28 1 7
+8 28 2 7
+8 28 3 7
+8 28 4 7
+8 28 5 7
+9 47 1 7
+9 47 2 7
+9 47 3 7
+9 47 4 7
+9 47 5 7
+9 163 1 14
+9 163 2 14
+9 163 3 14
+9 163 4 14
+9 163 5 14
+9 176 1 2
+9 176 2 2
+9 176 3 2
+9 176 4 2
+9 176 5 2
+9 59 1 1
+9 59 2 1
+9 59 3 1
+9 59 4 1
+9 59 5 1
+9 76 1 1
+9 76 2 1
+9 76 3 1
+9 76 4 1
+9 76 5 1
+9 260 1 7
+9 260 2 7
+9 260 3 7
+9 260 4 7
+9 260 5 7
+9 324 1 3
+9 324 2 3
+9 324 3 3
+9 324 4 3
+9 324 5 3
+9 160 1 13
+9 160 2 13
+9 160 3 13
+9 160 4 13
+9 160 5 13
+9 137 1 5
+9 137 2 5
+9 137 3 5
+9 137 4 5
+9 137 5 5
+9 476 1 7
+9 476 2 7
+9 476 3 7
+9 476 4 7
+9 476 5 7
+9 57 1 6
+9 57 2 6
+9 57 3 6
+9 57 4 6
+9 57 5 6
+9 204 1 1
+9 204 2 1
+9 204 3 1
+9 204 4 1
+9 204 5 1
+9 105 1 14
+9 105 2 14
+9 105 3 14
+9 105 4 14
+9 105 5 14
+9 307 1 5
+9 307 2 5
+9 307 3 5
+9 307 4 5
+9 307 5 5
+9 37 1 5
+9 37 2 5
+9 37 3 5
+9 37 4 5
+9 37 5 5
+9 297 1 9
+9 297 2 9
+9 297 3 9
+9 297 4 9
+9 297 5 9
+9 180 1 14
+9 180 2 14
+9 180 3 14
+9 180 4 14
+9 180 5 14
+9 503 1 15
+9 503 2 15
+9 503 3 15
+9 503 4 15
+9 503 5 15
+9 287 1 17
+9 287 2 17
+9 287 3 17
+9 287 4 17
+9 287 5 17
+9 325 1 1
+9 325 2 1
+9 325 3 1
+9 325 4 1
+9 325 5 1
+9 500 1 5
+9 500 2 5
+9 500 3 5
+9 500 4 5
+9 500 5 5
+9 119 1 14
+9 119 2 14
+9 119 3 14
+9 119 4 14
+9 119 5 14
+9 327 1 8
+9 327 2 8
+9 327 3 8
+9 327 4 8
+9 327 5 8
+9 83 1 3
+9 83 2 3
+9 83 3 3
+9 83 4 3
+9 83 5 3
+9 249 1 5
+9 249 2 5
+9 249 3 5
+9 249 4 5
+9 249 5 5
+9 230 1 17
+9 230 2 17
+9 230 3 17
+9 230 4 17
+9 230 5 17
+9 316 1 4
+9 316 2 4
+9 316 3 4
+9 316 4 4
+9 316 5 4
+9 424 1 0
+9 424 2 0
+9 424 3 0
+9 424 4 0
+9 424 5 0
+9 341 1 8
+9 341 2 8
+9 341 3 8
+9 341 4 8
+9 341 5 8
+9 478 1 9
+9 478 2 9
+9 478 3 9
+9 478 4 9
+9 478 5 9
+9 164 1 0
+9 164 2 0
+9 164 3 0
+9 164 4 0
+9 164 5 0
+9 319 1 12
+9 319 2 12
+9 319 3 12
+9 319 4 12
+9 319 5 12
+9 481 1 1
+9 481 2 1
+9 481 3 1
+9 481 4 1
+9 481 5 1
+9 218 1 0
+9 218 2 0
+9 218 3 0
+9 218 4 0
+9 218 5 0
+9 168 1 2
+9 168 2 2
+9 168 3 2
+9 168 4 2
+9 168 5 2
+9 54 1 1
+9 54 2 1
+9 54 3 1
+9 54 4 1
+9 54 5 1
+9 310 1 5
+9 310 2 5
+9 310 3 5
+9 310 4 5
+9 310 5 5
+9 186 1 17
+9 186 2 17
+9 186 3 17
+9 186 4 17
+9 186 5 17
+9 116 1 5
+9 116 2 5
+9 116 3 5
+9 116 4 5
+9 116 5 5
+9 335 1 7
+9 335 2 7
+9 335 3 7
+9 335 4 7
+9 335 5 7
+9 53 1 10
+9 53 2 10
+9 53 3 10
+9 53 4 10
+9 53 5 10
+9 67 1 5
+9 67 2 5
+9 67 3 5
+9 67 4 5
+9 67 5 5
+9 444 1 6
+9 444 2 6
+9 444 3 6
+9 444 4 6
+9 444 5 6
+9 368 1 12
+9 368 2 12
+9 368 3 12
+9 368 4 12
+9 368 5 12
+9 128 1 14
+9 128 2 14
+9 128 3 14
+9 128 4 14
+9 128 5 14
+9 157 1 8
+9 157 2 8
+9 157 3 8
+9 157 4 8
+9 157 5 8
+9 306 1 1
+9 306 2 1
+9 306 3 1
+9 306 4 1
+9 306 5 1
+9 35 1 7
+9 35 2 7
+9 35 3 7
+9 35 4 7
+9 35 5 7
+9 254 1 13
+9 254 2 13
+9 254 3 13
+9 254 4 13
+9 254 5 13
+9 467 1 2
+9 467 2 2
+9 467 3 2
+9 467 4 2
+9 467 5 2
+9 273 1 15
+9 273 2 15
+9 273 3 15
+9 273 4 15
+9 273 5 15
+9 23 1 5
+9 23 2 5
+9 23 3 5
+9 23 4 5
+9 23 5 5
+9 91 1 13
+9 91 2 13
+9 91 3 13
+9 91 4 13
+9 91 5 13
+9 342 1 2
+9 342 2 2
+9 342 3 2
+9 342 4 2
+9 342 5 2
+9 405 1 9
+9 405 2 9
+9 405 3 9
+9 405 4 9
+9 405 5 9
+9 413 1 4
+9 413 2 4
+9 413 3 4
+9 413 4 4
+9 413 5 4
+9 389 1 17
+9 389 2 17
+9 389 3 17
+9 389 4 17
+9 389 5 17
+9 123 1 7
+9 123 2 7
+9 123 3 7
+9 123 4 7
+9 123 5 7
+9 384 1 4
+9 384 2 4
+9 384 3 4
+9 384 4 4
+9 384 5 4
+9 299 1 5
+9 299 2 5
+9 299 3 5
+9 299 4 5
+9 299 5 5
+9 48 1 0
+9 48 2 0
+9 48 3 0
+9 48 4 0
+9 48 5 0
+9 248 1 15
+9 248 2 15
+9 248 3 15
+9 248 4 15
+9 248 5 15
+9 151 1 12
+9 151 2 12
+9 151 3 12
+9 151 4 12
+9 151 5 12
+9 477 1 12
+9 477 2 12
+9 477 3 12
+9 477 4 12
+9 477 5 12
+10 436 1 5
+10 436 2 5
+10 436 3 5
+10 436 4 5
+10 436 5 5
+10 128 1 14
+10 128 2 14
+10 128 3 14
+10 128 4 14
+10 128 5 14
+10 545 1 7
+10 545 2 7
+10 545 3 7
+10 545 4 7
+10 545 5 7
+10 332 1 1
+10 332 2 1
+10 332 3 1
+10 332 4 1
+10 332 5 1
+10 758 1 8
+10 758 2 8
+10 758 3 8
+10 758 4 8
+10 758 5 8
+10 625 1 14
+10 625 2 14
+10 625 3 14
+10 625 4 14
+10 625 5 14
+10 160 1 13
+10 160 2 13
+10 160 3 13
+10 160 4 13
+10 160 5 13
+10 194 1 6
+10 194 2 6
+10 194 3 6
+10 194 4 6
+10 194 5 6
+10 172 1 4
+10 172 2 4
+10 172 3 4
+10 172 4 4
+10 172 5 4
+10 866 1 5
+10 866 2 5
+10 866 3 5
+10 866 4 5
+10 866 5 5
+10 120 1 15
+10 120 2 15
+10 120 3 15
+10 120 4 15
+10 120 5 15
+10 923 1 3
+10 923 2 3
+10 923 3 3
+10 923 4 3
+10 923 5 3
+10 813 1 1
+10 813 2 1
+10 813 3 1
+10 813 4 1
+10 813 5 1
+10 493 1 1
+10 493 2 1
+10 493 3 1
+10 493 4 1
+10 493 5 1
+10 748 1 8
+10 748 2 8
+10 748 3 8
+10 748 4 8
+10 748 5 8
+10 104 1 1
+10 104 2 1
+10 104 3 1
+10 104 4 1
+10 104 5 1
+10 326 1 7
+10 326 2 7
+10 326 3 7
+10 326 4 7
+10 326 5 7
+10 573 1 7
+10 573 2 7
+10 573 3 7
+10 573 4 7
+10 573 5 7
+10 754 1 13
+10 754 2 13
+10 754 3 13
+10 754 4 13
+10 754 5 13
+10 146 1 5
+10 146 2 5
+10 146 3 5
+10 146 4 5
+10 146 5 5
+10 697 1 14
+10 697 2 14
+10 697 3 14
+10 697 4 14
+10 697 5 14
+10 150 1 9
+10 150 2 9
+10 150 3 9
+10 150 4 9
+10 150 5 9
+10 948 1 7
+10 948 2 7
+10 948 3 7
+10 948 4 7
+10 948 5 7
+10 726 1 14
+10 726 2 14
+10 726 3 14
+10 726 4 14
+10 726 5 14
+10 698 1 3
+10 698 2 3
+10 698 3 3
+10 698 4 3
+10 698 5 3
+10 974 1 9
+10 974 2 9
+10 974 3 9
+10 974 4 9
+10 974 5 9
+10 787 1 5
+10 787 2 5
+10 787 3 5
+10 787 4 5
+10 787 5 5
+10 449 1 5
+10 449 2 5
+10 449 3 5
+10 449 4 5
+10 449 5 5
+10 624 1 15
+10 624 2 15
+10 624 3 15
+10 624 4 15
+10 624 5 15
+10 972 1 1
+10 972 2 1
+10 972 3 1
+10 972 4 1
+10 972 5 1
+10 31 1 8
+10 31 2 8
+10 31 3 8
+10 31 4 8
+10 31 5 8
+10 568 1 17
+10 568 2 17
+10 568 3 17
+10 568 4 17
+10 568 5 17
+10 890 1 6
+10 890 2 6
+10 890 3 6
+10 890 4 6
+10 890 5 6
+10 16 1 7
+10 16 2 7
+10 16 3 7
+10 16 4 7
+10 16 5 7
+10 416 1 7
+10 416 2 7
+10 416 3 7
+10 416 4 7
+10 416 5 7
+10 499 1 5
+10 499 2 5
+10 499 3 5
+10 499 4 5
+10 499 5 5
+10 615 1 0
+10 615 2 0
+10 615 3 0
+10 615 4 0
+10 615 5 0
+10 555 1 8
+10 555 2 8
+10 555 3 8
+10 555 4 8
+10 555 5 8
+10 144 1 6
+10 144 2 6
+10 144 3 6
+10 144 4 6
+10 144 5 6
+10 509 1 17
+10 509 2 17
+10 509 3 17
+10 509 4 17
+10 509 5 17
+10 316 1 4
+10 316 2 4
+10 316 3 4
+10 316 4 4
+10 316 5 4
+10 66 1 14
+10 66 2 14
+10 66 3 14
+10 66 4 14
+10 66 5 14
+10 671 1 10
+10 671 2 10
+10 671 3 10
+10 671 4 10
+10 671 5 10
+10 310 1 5
+10 310 2 5
+10 310 3 5
+10 310 4 5
+10 310 5 5
+10 499 1 5
+10 499 2 5
+10 499 3 5
+10 499 4 5
+10 499 5 5
+10 911 1 8
+10 911 2 8
+10 911 3 8
+10 911 4 8
+10 911 5 8
+10 174 1 6
+10 174 2 6
+10 174 3 6
+10 174 4 6
+10 174 5 6
+10 721 1 5
+10 721 2 5
+10 721 3 5
+10 721 4 5
+10 721 5 5
+10 246 1 17
+10 246 2 17
+10 246 3 17
+10 246 4 17
+10 246 5 17
+10 736 1 0
+10 736 2 0
+10 736 3 0
+10 736 4 0
+10 736 5 0
+10 340 1 5
+10 340 2 5
+10 340 3 5
+10 340 4 5
+10 340 5 5
+10 214 1 17
+10 214 2 17
+10 214 3 17
+10 214 4 17
+10 214 5 17
+10 936 1 17
+10 936 2 17
+10 936 3 17
+10 936 4 17
+10 936 5 17
+10 278 1 14
+10 278 2 14
+10 278 3 14
+10 278 4 14
+10 278 5 14
+10 860 1 9
+10 860 2 9
+10 860 3 9
+10 860 4 9
+10 860 5 9
+10 673 1 3
+10 673 2 3
+10 673 3 3
+10 673 4 3
+10 673 5 3
+10 732 1 14
+10 732 2 14
+10 732 3 14
+10 732 4 14
+10 732 5 14
+10 936 1 17
+10 936 2 17
+10 936 3 17
+10 936 4 17
+10 936 5 17
+10 69 1 1
+10 69 2 1
+10 69 3 1
+10 69 4 1
+10 69 5 1
+10 865 1 14
+10 865 2 14
+10 865 3 14
+10 865 4 14
+10 865 5 14
+10 348 1 14
+10 348 2 14
+10 348 3 14
+10 348 4 14
+10 348 5 14
+10 285 1 9
+10 285 2 9
+10 285 3 9
+10 285 4 9
+10 285 5 9
+10 705 1 6
+10 705 2 6
+10 705 3 6
+10 705 4 6
+10 705 5 6
+10 154 1 13
+10 154 2 13
+10 154 3 13
+10 154 4 13
+10 154 5 13
+11 1671 1 3
+11 1671 2 3
+11 1671 3 3
+11 1671 4 3
+11 1671 5 3
+11 1334 1 1
+11 1334 2 1
+11 1334 3 1
+11 1334 4 1
+11 1334 5 1
+11 763 1 7
+11 763 2 7
+11 763 3 7
+11 763 4 7
+11 763 5 7
+11 1607 1 1
+11 1607 2 1
+11 1607 3 1
+11 1607 4 1
+11 1607 5 1
+11 1725 1 0
+11 1725 2 0
+11 1725 3 0
+11 1725 4 0
+11 1725 5 0
+11 162 1 14
+11 162 2 14
+11 162 3 14
+11 162 4 14
+11 162 5 14
+11 1068 1 4
+11 1068 2 4
+11 1068 3 4
+11 1068 4 4
+11 1068 5 4
+11 1207 1 14
+11 1207 2 14
+11 1207 3 14
+11 1207 4 14
+11 1207 5 14
+11 501 1 6
+11 501 2 6
+11 501 3 6
+11 501 4 6
+11 501 5 6
+11 1419 1 7
+11 1419 2 7
+11 1419 3 7
+11 1419 4 7
+11 1419 5 7
+11 440 1 14
+11 440 2 14
+11 440 3 14
+11 440 4 14
+11 440 5 14
+11 512 1 6
+11 512 2 6
+11 512 3 6
+11 512 4 6
+11 512 5 6
+11 1260 1 4
+11 1260 2 4
+11 1260 3 4
+11 1260 4 4
+11 1260 5 4
+11 1626 1 0
+11 1626 2 0
+11 1626 3 0
+11 1626 4 0
+11 1626 5 0
+11 1023 1 2
+11 1023 2 2
+11 1023 3 2
+11 1023 4 2
+11 1023 5 2
+11 510 1 14
+11 510 2 14
+11 510 3 14
+11 510 4 14
+11 510 5 14
+11 960 1 15
+11 960 2 15
+11 960 3 15
+11 960 4 15
+11 960 5 15
+11 1403 1 4
+11 1403 2 4
+11 1403 3 4
+11 1403 4 4
+11 1403 5 4
+11 1281 1 0
+11 1281 2 0
+11 1281 3 0
+11 1281 4 0
+11 1281 5 0
+11 1230 1 8
+11 1230 2 8
+11 1230 3 8
+11 1230 4 8
+11 1230 5 8
+11 631 1 4
+11 631 2 4
+11 631 3 4
+11 631 4 4
+11 631 5 4
+11 481 1 1
+11 481 2 1
+11 481 3 1
+11 481 4 1
+11 481 5 1
+11 229 1 12
+11 229 2 12
+11 229 3 12
+11 229 4 12
+11 229 5 12
+11 853 1 15
+11 853 2 15
+11 853 3 15
+11 853 4 15
+11 853 5 15
+11 1401 1 17
+11 1401 2 17
+11 1401 3 17
+11 1401 4 17
+11 1401 5 17
+11 896 1 4
+11 896 2 4
+11 896 3 4
+11 896 4 4
+11 896 5 4
+11 1654 1 7
+11 1654 2 7
+11 1654 3 7
+11 1654 4 7
+11 1654 5 7
+11 953 1 5
+11 953 2 5
+11 953 3 5
+11 953 4 5
+11 953 5 5
+11 530 1 6
+11 530 2 6
+11 530 3 6
+11 530 4 6
+11 530 5 6
+11 2002 1 12
+11 2002 2 12
+11 2002 3 12
+11 2002 4 12
+11 2002 5 12
+11 1953 1 2
+11 1953 2 2
+11 1953 3 2
+11 1953 4 2
+11 1953 5 2
+11 1509 1 4
+11 1509 2 4
+11 1509 3 4
+11 1509 4 4
+11 1509 5 4
+11 1778 1 10
+11 1778 2 10
+11 1778 3 10
+11 1778 4 10
+11 1778 5 10
+11 1619 1 14
+11 1619 2 14
+11 1619 3 14
+11 1619 4 14
+11 1619 5 14
+11 504 1 2
+11 504 2 2
+11 504 3 2
+11 504 4 2
+11 504 5 2
+11 9 1 5
+11 9 2 5
+11 9 3 5
+11 9 4 5
+11 9 5 5
+11 1196 1 14
+11 1196 2 14
+11 1196 3 14
+11 1196 4 14
+11 1196 5 14
+11 1285 1 12
+11 1285 2 12
+11 1285 3 12
+11 1285 4 12
+11 1285 5 12
+11 1842 1 5
+11 1842 2 5
+11 1842 3 5
+11 1842 4 5
+11 1842 5 5
+11 792 1 12
+11 792 2 12
+11 792 3 12
+11 792 4 12
+11 792 5 12
+11 1594 1 12
+11 1594 2 12
+11 1594 3 12
+11 1594 4 12
+11 1594 5 12
+11 1261 1 5
+11 1261 2 5
+11 1261 3 5
+11 1261 4 5
+11 1261 5 5
+11 1448 1 0
+11 1448 2 0
+11 1448 3 0
+11 1448 4 0
+11 1448 5 0
+11 1865 1 9
+11 1865 2 9
+11 1865 3 9
+11 1865 4 9
+11 1865 5 9
+11 375 1 4
+11 375 2 4
+11 375 3 4
+11 375 4 4
+11 375 5 4
+11 1684 1 9
+11 1684 2 9
+11 1684 3 9
+11 1684 4 9
+11 1684 5 9
+11 218 1 0
+11 218 2 0
+11 218 3 0
+11 218 4 0
+11 218 5 0
+11 151 1 12
+11 151 2 12
+11 151 3 12
+11 151 4 12
+11 151 5 12
+11 1956 1 10
+11 1956 2 10
+11 1956 3 10
+11 1956 4 10
+11 1956 5 10
+11 1670 1 9
+11 1670 2 9
+11 1670 3 9
+11 1670 4 9
+11 1670 5 9
+11 488 1 1
+11 488 2 1
+11 488 3 1
+11 488 4 1
+11 488 5 1
+11 833 1 7
+11 833 2 7
+11 833 3 7
+11 833 4 7
+11 833 5 7
+11 1508 1 6
+11 1508 2 6
+11 1508 3 6
+11 1508 4 6
+11 1508 5 6
+11 470 1 12
+11 470 2 12
+11 470 3 12
+11 470 4 12
+11 470 5 12
+11 26 1 8
+11 26 2 8
+11 26 3 8
+11 26 4 8
+11 26 5 8
+11 74 1 12
+11 74 2 12
+11 74 3 12
+11 74 4 12
+11 74 5 12
+11 1471 1 10
+11 1471 2 10
+11 1471 3 10
+11 1471 4 10
+11 1471 5 10
+11 665 1 5
+11 665 2 5
+11 665 3 5
+11 665 4 5
+11 665 5 5
+11 345 1 12
+11 345 2 12
+11 345 3 12
+11 345 4 12
+11 345 5 12
+11 506 1 5
+11 506 2 5
+11 506 3 5
+11 506 4 5
+11 506 5 5
+11 1443 1 14
+11 1443 2 14
+11 1443 3 14
+11 1443 4 14
+11 1443 5 14
+11 1126 1 10
+11 1126 2 10
+11 1126 3 10
+11 1126 4 10
+11 1126 5 10
+11 691 1 12
+11 691 2 12
+11 691 3 12
+11 691 4 12
+11 691 5 12
+11 91 1 13
+11 91 2 13
+11 91 3 13
+11 91 4 13
+11 91 5 13
+12 2730 1 8
+12 2730 2 8
+12 2730 3 8
+12 2730 4 8
+12 2730 5 8
+12 2246 1 2
+12 2246 2 2
+12 2246 3 2
+12 2246 4 2
+12 2246 5 2
+12 3903 1 12
+12 3903 2 12
+12 3903 3 12
+12 3903 4 12
+12 3903 5 12
+12 811 1 1
+12 811 2 1
+12 811 3 1
+12 811 4 1
+12 811 5 1
+12 3489 1 5
+12 3489 2 5
+12 3489 3 5
+12 3489 4 5
+12 3489 5 5
+12 918 1 6
+12 918 2 6
+12 918 3 6
+12 918 4 6
+12 918 5 6
+12 2536 1 9
+12 2536 2 9
+12 2536 3 9
+12 2536 4 9
+12 2536 5 9
+12 126 1 10
+12 126 2 10
+12 126 3 10
+12 126 4 10
+12 126 5 10
+12 102 1 6
+12 102 2 6
+12 102 3 6
+12 102 4 6
+12 102 5 6
+12 3157 1 8
+12 3157 2 8
+12 3157 3 8
+12 3157 4 8
+12 3157 5 8
+12 2042 1 14
+12 2042 2 14
+12 2042 3 14
+12 2042 4 14
+12 2042 5 14
+12 509 1 17
+12 509 2 17
+12 509 3 17
+12 509 4 17
+12 509 5 17
+12 1445 1 4
+12 1445 2 4
+12 1445 3 4
+12 1445 4 4
+12 1445 5 4
+12 1146 1 5
+12 1146 2 5
+12 1146 3 5
+12 1146 4 5
+12 1146 5 5
+12 1373 1 12
+12 1373 2 12
+12 1373 3 12
+12 1373 4 12
+12 1373 5 12
+12 1513 1 15
+12 1513 2 15
+12 1513 3 15
+12 1513 4 15
+12 1513 5 15
+12 3105 1 7
+12 3105 2 7
+12 3105 3 7
+12 3105 4 7
+12 3105 5 7
+12 2481 1 12
+12 2481 2 12
+12 2481 3 12
+12 2481 4 12
+12 2481 5 12
+12 1869 1 6
+12 1869 2 6
+12 1869 3 6
+12 1869 4 6
+12 1869 5 6
+12 1527 1 12
+12 1527 2 12
+12 1527 3 12
+12 1527 4 12
+12 1527 5 12
+12 3375 1 4
+12 3375 2 4
+12 3375 3 4
+12 3375 4 4
+12 3375 5 4
+12 2135 1 12
+12 2135 2 12
+12 2135 3 12
+12 2135 4 12
+12 2135 5 12
+12 729 1 7
+12 729 2 7
+12 729 3 7
+12 729 4 7
+12 729 5 7
+12 464 1 17
+12 464 2 17
+12 464 3 17
+12 464 4 17
+12 464 5 17
+12 2872 1 12
+12 2872 2 12
+12 2872 3 12
+12 2872 4 12
+12 2872 5 12
+12 3583 1 15
+12 3583 2 15
+12 3583 3 15
+12 3583 4 15
+12 3583 5 15
+12 869 1 2
+12 869 2 2
+12 869 3 2
+12 869 4 2
+12 869 5 2
+12 2447 1 1
+12 2447 2 1
+12 2447 3 1
+12 2447 4 1
+12 2447 5 1
+12 59 1 1
+12 59 2 1
+12 59 3 1
+12 59 4 1
+12 59 5 1
+12 3055 1 9
+12 3055 2 9
+12 3055 3 9
+12 3055 4 9
+12 3055 5 9
+12 296 1 3
+12 296 2 3
+12 296 3 3
+12 296 4 3
+12 296 5 3
+12 2118 1 10
+12 2118 2 10
+12 2118 3 10
+12 2118 4 10
+12 2118 5 10
+12 3144 1 6
+12 3144 2 6
+12 3144 3 6
+12 3144 4 6
+12 3144 5 6
+12 2467 1 8
+12 2467 2 8
+12 2467 3 8
+12 2467 4 8
+12 2467 5 8
+12 1967 1 3
+12 1967 2 3
+12 1967 3 3
+12 1967 4 3
+12 1967 5 3
+12 3705 1 8
+12 3705 2 8
+12 3705 3 8
+12 3705 4 8
+12 3705 5 8
+12 1030 1 14
+12 1030 2 14
+12 1030 3 14
+12 1030 4 14
+12 1030 5 14
+12 1865 1 9
+12 1865 2 9
+12 1865 3 9
+12 1865 4 9
+12 1865 5 9
+12 3160 1 4
+12 3160 2 4
+12 3160 3 4
+12 3160 4 4
+12 3160 5 4
+12 3232 1 12
+12 3232 2 12
+12 3232 3 12
+12 3232 4 12
+12 3232 5 12
+12 3886 1 4
+12 3886 2 4
+12 3886 3 4
+12 3886 4 4
+12 3886 5 4
+12 68 1 6
+12 68 2 6
+12 68 3 6
+12 68 4 6
+12 68 5 6
+12 1240 1 4
+12 1240 2 4
+12 1240 3 4
+12 1240 4 4
+12 1240 5 4
+12 3498 1 9
+12 3498 2 9
+12 3498 3 9
+12 3498 4 9
+12 3498 5 9
+12 1805 1 8
+12 1805 2 8
+12 1805 3 8
+12 1805 4 8
+12 1805 5 8
+12 3498 1 9
+12 3498 2 9
+12 3498 3 9
+12 3498 4 9
+12 3498 5 9
+12 3510 1 1
+12 3510 2 1
+12 3510 3 1
+12 3510 4 1
+12 3510 5 1
+12 373 1 10
+12 373 2 10
+12 373 3 10
+12 373 4 10
+12 373 5 10
+12 1286 1 15
+12 1286 2 15
+12 1286 3 15
+12 1286 4 15
+12 1286 5 15
+12 2246 1 2
+12 2246 2 2
+12 2246 3 2
+12 2246 4 2
+12 2246 5 2
+12 205 1 5
+12 205 2 5
+12 205 3 5
+12 205 4 5
+12 205 5 5
+12 1879 1 0
+12 1879 2 0
+12 1879 3 0
+12 1879 4 0
+12 1879 5 0
+12 270 1 13
+12 270 2 13
+12 270 3 13
+12 270 4 13
+12 270 5 13
+12 3478 1 8
+12 3478 2 8
+12 3478 3 8
+12 3478 4 8
+12 3478 5 8
+12 3022 1 14
+12 3022 2 14
+12 3022 3 14
+12 3022 4 14
+12 3022 5 14
+12 2200 1 0
+12 2200 2 0
+12 2200 3 0
+12 2200 4 0
+12 2200 5 0
+12 46 1 5
+12 46 2 5
+12 46 3 5
+12 46 4 5
+12 46 5 5
+12 3405 1 1
+12 3405 2 1
+12 3405 3 1
+12 3405 4 1
+12 3405 5 1
+12 1724 1 4
+12 1724 2 4
+12 1724 3 4
+12 1724 4 4
+12 1724 5 4
+12 757 1 7
+12 757 2 7
+12 757 3 7
+12 757 4 7
+12 757 5 7
+12 773 1 8
+12 773 2 8
+12 773 3 8
+12 773 4 8
+12 773 5 8
+12 211 1 3
+12 211 2 3
+12 211 3 3
+12 211 4 3
+12 211 5 3
+12 2670 1 12
+12 2670 2 12
+12 2670 3 12
+12 2670 4 12
+12 2670 5 12
+12 799 1 6
+12 799 2 6
+12 799 3 6
+12 799 4 6
+12 799 5 6
+13 893 1 6
+13 893 2 6
+13 893 3 6
+13 893 4 6
+13 893 5 6
+13 380 1 12
+13 380 2 12
+13 380 3 12
+13 380 4 12
+13 380 5 12
+13 4122 1 12
+13 4122 2 12
+13 4122 3 12
+13 4122 4 12
+13 4122 5 12
+13 5157 1 14
+13 5157 2 14
+13 5157 3 14
+13 5157 4 14
+13 5157 5 14
+13 5480 1 15
+13 5480 2 15
+13 5480 3 15
+13 5480 4 15
+13 5480 5 15
+13 5574 1 17
+13 5574 2 17
+13 5574 3 17
+13 5574 4 17
+13 5574 5 17
+13 2420 1 6
+13 2420 2 6
+13 2420 3 6
+13 2420 4 6
+13 2420 5 6
+13 7282 1 7
+13 7282 2 7
+13 7282 3 7
+13 7282 4 7
+13 7282 5 7
+13 4528 1 3
+13 4528 2 3
+13 4528 3 3
+13 4528 4 3
+13 4528 5 3
+13 637 1 6
+13 637 2 6
+13 637 3 6
+13 637 4 6
+13 637 5 6
+13 2363 1 9
+13 2363 2 9
+13 2363 3 9
+13 2363 4 9
+13 2363 5 9
+13 99 1 2
+13 99 2 2
+13 99 3 2
+13 99 4 2
+13 99 5 2
+13 1892 1 9
+13 1892 2 9
+13 1892 3 9
+13 1892 4 9
+13 1892 5 9
+13 231 1 2
+13 231 2 2
+13 231 3 2
+13 231 4 2
+13 231 5 2
+13 2672 1 15
+13 2672 2 15
+13 2672 3 15
+13 2672 4 15
+13 2672 5 15
+13 4991 1 2
+13 4991 2 2
+13 4991 3 2
+13 4991 4 2
+13 4991 5 2
+13 2715 1 15
+13 2715 2 15
+13 2715 3 15
+13 2715 4 15
+13 2715 5 15
+13 239 1 3
+13 239 2 3
+13 239 3 3
+13 239 4 3
+13 239 5 3
+13 6492 1 7
+13 6492 2 7
+13 6492 3 7
+13 6492 4 7
+13 6492 5 7
+13 1587 1 9
+13 1587 2 9
+13 1587 3 9
+13 1587 4 9
+13 1587 5 9
+13 4333 1 5
+13 4333 2 5
+13 4333 3 5
+13 4333 4 5
+13 4333 5 5
+13 6561 1 5
+13 6561 2 5
+13 6561 3 5
+13 6561 4 5
+13 6561 5 5
+13 6154 1 8
+13 6154 2 8
+13 6154 3 8
+13 6154 4 8
+13 6154 5 8
+13 7759 1 7
+13 7759 2 7
+13 7759 3 7
+13 7759 4 7
+13 7759 5 7
+13 7672 1 0
+13 7672 2 0
+13 7672 3 0
+13 7672 4 0
+13 7672 5 0
+13 2481 1 12
+13 2481 2 12
+13 2481 3 12
+13 2481 4 12
+13 2481 5 12
+13 4808 1 4
+13 4808 2 4
+13 4808 3 4
+13 4808 4 4
+13 4808 5 4
+13 8071 1 6
+13 8071 2 6
+13 8071 3 6
+13 8071 4 6
+13 8071 5 6
+13 8156 1 10
+13 8156 2 10
+13 8156 3 10
+13 8156 4 10
+13 8156 5 10
+13 2037 1 12
+13 2037 2 12
+13 2037 3 12
+13 2037 4 12
+13 2037 5 12
+13 1194 1 6
+13 1194 2 6
+13 1194 3 6
+13 1194 4 6
+13 1194 5 6
+13 1011 1 7
+13 1011 2 7
+13 1011 3 7
+13 1011 4 7
+13 1011 5 7
+13 7104 1 9
+13 7104 2 9
+13 7104 3 9
+13 7104 4 9
+13 7104 5 9
+13 999 1 13
+13 999 2 13
+13 999 3 13
+13 999 4 13
+13 999 5 13
+13 3079 1 10
+13 3079 2 10
+13 3079 3 10
+13 3079 4 10
+13 3079 5 10
+13 1167 1 15
+13 1167 2 15
+13 1167 3 15
+13 1167 4 15
+13 1167 5 15
+13 2635 1 6
+13 2635 2 6
+13 2635 3 6
+13 2635 4 6
+13 2635 5 6
+13 5668 1 0
+13 5668 2 0
+13 5668 3 0
+13 5668 4 0
+13 5668 5 0
+13 3834 1 9
+13 3834 2 9
+13 3834 3 9
+13 3834 4 9
+13 3834 5 9
+13 4540 1 10
+13 4540 2 10
+13 4540 3 10
+13 4540 4 10
+13 4540 5 10
+13 1067 1 14
+13 1067 2 14
+13 1067 3 14
+13 1067 4 14
+13 1067 5 14
+13 239 1 3
+13 239 2 3
+13 239 3 3
+13 239 4 3
+13 239 5 3
+13 4066 1 15
+13 4066 2 15
+13 4066 3 15
+13 4066 4 15
+13 4066 5 15
+13 7101 1 12
+13 7101 2 12
+13 7101 3 12
+13 7101 4 12
+13 7101 5 12
+13 7826 1 3
+13 7826 2 3
+13 7826 3 3
+13 7826 4 3
+13 7826 5 3
+13 174 1 6
+13 174 2 6
+13 174 3 6
+13 174 4 6
+13 174 5 6
+13 4578 1 14
+13 4578 2 14
+13 4578 3 14
+13 4578 4 14
+13 4578 5 14
+13 2875 1 1
+13 2875 2 1
+13 2875 3 1
+13 2875 4 1
+13 2875 5 1
+13 6067 1 10
+13 6067 2 10
+13 6067 3 10
+13 6067 4 10
+13 6067 5 10
+13 3180 1 2
+13 3180 2 2
+13 3180 3 2
+13 3180 4 2
+13 3180 5 2
+13 3426 1 6
+13 3426 2 6
+13 3426 3 6
+13 3426 4 6
+13 3426 5 6
+13 2498 1 8
+13 2498 2 8
+13 2498 3 8
+13 2498 4 8
+13 2498 5 8
+13 4938 1 6
+13 4938 2 6
+13 4938 3 6
+13 4938 4 6
+13 4938 5 6
+13 1622 1 10
+13 1622 2 10
+13 1622 3 10
+13 1622 4 10
+13 1622 5 10
+13 5260 1 9
+13 5260 2 9
+13 5260 3 9
+13 5260 4 9
+13 5260 5 9
+13 6721 1 17
+13 6721 2 17
+13 6721 3 17
+13 6721 4 17
+13 6721 5 17
+13 1809 1 3
+13 1809 2 3
+13 1809 3 3
+13 1809 4 3
+13 1809 5 3
+13 7230 1 14
+13 7230 2 14
+13 7230 3 14
+13 7230 4 14
+13 7230 5 14
+13 2000 1 8
+13 2000 2 8
+13 2000 3 8
+13 2000 4 8
+13 2000 5 8
+13 398 1 6
+13 398 2 6
+13 398 3 6
+13 398 4 6
+13 398 5 6
+13 5964 1 9
+13 5964 2 9
+13 5964 3 9
+13 5964 4 9
+13 5964 5 9
+13 6171 1 15
+13 6171 2 15
+13 6171 3 15
+13 6171 4 15
+13 6171 5 15
+13 6752 1 2
+13 6752 2 2
+13 6752 3 2
+13 6752 4 2
+13 6752 5 2
+13 7904 1 6
+13 7904 2 6
+13 7904 3 6
+13 7904 4 6
+13 7904 5 6
+14 2306 1 6
+14 2306 2 6
+14 2306 3 6
+14 2306 4 6
+14 2306 5 6
+14 1881 1 7
+14 1881 2 7
+14 1881 3 7
+14 1881 4 7
+14 1881 5 7
+14 11659 1 4
+14 11659 2 4
+14 11659 3 4
+14 11659 4 4
+14 11659 5 4
+14 12598 1 3
+14 12598 2 3
+14 12598 3 3
+14 12598 4 3
+14 12598 5 3
+14 15891 1 9
+14 15891 2 9
+14 15891 3 9
+14 15891 4 9
+14 15891 5 9
+14 7988 1 15
+14 7988 2 15
+14 7988 3 15
+14 7988 4 15
+14 7988 5 15
+14 2768 1 2
+14 2768 2 2
+14 2768 3 2
+14 2768 4 2
+14 2768 5 2
+14 2197 1 13
+14 2197 2 13
+14 2197 3 13
+14 2197 4 13
+14 2197 5 13
+14 15826 1 10
+14 15826 2 10
+14 15826 3 10
+14 15826 4 10
+14 15826 5 10
+14 4100 1 1
+14 4100 2 1
+14 4100 3 1
+14 4100 4 1
+14 4100 5 1
+14 5497 1 8
+14 5497 2 8
+14 5497 3 8
+14 5497 4 8
+14 5497 5 8
+14 1329 1 14
+14 1329 2 14
+14 1329 3 14
+14 1329 4 14
+14 1329 5 14
+14 4648 1 7
+14 4648 2 7
+14 4648 3 7
+14 4648 4 7
+14 4648 5 7
+14 11168 1 13
+14 11168 2 13
+14 11168 3 13
+14 11168 4 13
+14 11168 5 13
+14 2871 1 0
+14 2871 2 0
+14 2871 3 0
+14 2871 4 0
+14 2871 5 0
+14 6846 1 2
+14 6846 2 2
+14 6846 3 2
+14 6846 4 2
+14 6846 5 2
+14 7982 1 15
+14 7982 2 15
+14 7982 3 15
+14 7982 4 15
+14 7982 5 15
+14 2869 1 10
+14 2869 2 10
+14 2869 3 10
+14 2869 4 10
+14 2869 5 10
+14 13103 1 3
+14 13103 2 3
+14 13103 3 3
+14 13103 4 3
+14 13103 5 3
+14 9600 1 14
+14 9600 2 14
+14 9600 3 14
+14 9600 4 14
+14 9600 5 14
+14 13746 1 9
+14 13746 2 9
+14 13746 3 9
+14 13746 4 9
+14 13746 5 9
+14 9665 1 6
+14 9665 2 6
+14 9665 3 6
+14 9665 4 6
+14 9665 5 6
+14 6264 1 15
+14 6264 2 15
+14 6264 3 15
+14 6264 4 15
+14 6264 5 15
+14 10450 1 3
+14 10450 2 3
+14 10450 3 3
+14 10450 4 3
+14 10450 5 3
+14 13753 1 14
+14 13753 2 14
+14 13753 3 14
+14 13753 4 14
+14 13753 5 14
+14 13977 1 6
+14 13977 2 6
+14 13977 3 6
+14 13977 4 6
+14 13977 5 6
+14 5279 1 17
+14 5279 2 17
+14 5279 3 17
+14 5279 4 17
+14 5279 5 17
+14 7584 1 15
+14 7584 2 15
+14 7584 3 15
+14 7584 4 15
+14 7584 5 15
+14 247 1 17
+14 247 2 17
+14 247 3 17
+14 247 4 17
+14 247 5 17
+14 13284 1 7
+14 13284 2 7
+14 13284 3 7
+14 13284 4 7
+14 13284 5 7
+14 10789 1 6
+14 10789 2 6
+14 10789 3 6
+14 10789 4 6
+14 10789 5 6
+14 4332 1 3
+14 4332 2 3
+14 4332 3 3
+14 4332 4 3
+14 4332 5 3
+14 15705 1 13
+14 15705 2 13
+14 15705 3 13
+14 15705 4 13
+14 15705 5 13
+14 5405 1 8
+14 5405 2 8
+14 5405 3 8
+14 5405 4 8
+14 5405 5 8
+14 12031 1 14
+14 12031 2 14
+14 12031 3 14
+14 12031 4 14
+14 12031 5 14
+14 4684 1 15
+14 4684 2 15
+14 4684 3 15
+14 4684 4 15
+14 4684 5 15
+14 10107 1 14
+14 10107 2 14
+14 10107 3 14
+14 10107 4 14
+14 10107 5 14
+14 10645 1 4
+14 10645 2 4
+14 10645 3 4
+14 10645 4 4
+14 10645 5 4
+14 1814 1 8
+14 1814 2 8
+14 1814 3 8
+14 1814 4 8
+14 1814 5 8
+14 12906 1 0
+14 12906 2 0
+14 12906 3 0
+14 12906 4 0
+14 12906 5 0
+14 13619 1 5
+14 13619 2 5
+14 13619 3 5
+14 13619 4 5
+14 13619 5 5
+14 16110 1 3
+14 16110 2 3
+14 16110 3 3
+14 16110 4 3
+14 16110 5 3
+14 11973 1 12
+14 11973 2 12
+14 11973 3 12
+14 11973 4 12
+14 11973 5 12
+14 4483 1 13
+14 4483 2 13
+14 4483 3 13
+14 4483 4 13
+14 4483 5 13
+14 2052 1 1
+14 2052 2 1
+14 2052 3 1
+14 2052 4 1
+14 2052 5 1
+14 6049 1 7
+14 6049 2 7
+14 6049 3 7
+14 6049 4 7
+14 6049 5 7
+14 5470 1 17
+14 5470 2 17
+14 5470 3 17
+14 5470 4 17
+14 5470 5 17
+14 15849 1 4
+14 15849 2 4
+14 15849 3 4
+14 15849 4 4
+14 15849 5 4
+14 12203 1 0
+14 12203 2 0
+14 12203 3 0
+14 12203 4 0
+14 12203 5 0
+14 12665 1 12
+14 12665 2 12
+14 12665 3 12
+14 12665 4 12
+14 12665 5 12
+14 1957 1 7
+14 1957 2 7
+14 1957 3 7
+14 1957 4 7
+14 1957 5 7
+14 8833 1 17
+14 8833 2 17
+14 8833 3 17
+14 8833 4 17
+14 8833 5 17
+14 15511 1 13
+14 15511 2 13
+14 15511 3 13
+14 15511 4 13
+14 15511 5 13
+14 7190 1 6
+14 7190 2 6
+14 7190 3 6
+14 7190 4 6
+14 7190 5 6
+14 10835 1 17
+14 10835 2 17
+14 10835 3 17
+14 10835 4 17
+14 10835 5 17
+14 1350 1 2
+14 1350 2 2
+14 1350 3 2
+14 1350 4 2
+14 1350 5 2
+14 8808 1 7
+14 8808 2 7
+14 8808 3 7
+14 8808 4 7
+14 8808 5 7
+14 8043 1 13
+14 8043 2 13
+14 8043 3 13
+14 8043 4 13
+14 8043 5 13
+14 1172 1 14
+14 1172 2 14
+14 1172 3 14
+14 1172 4 14
+14 1172 5 14
+14 5572 1 17
+14 5572 2 17
+14 5572 3 17
+14 5572 4 17
+14 5572 5 17
+14 10871 1 1
+14 10871 2 1
+14 10871 3 1
+14 10871 4 1
+14 10871 5 1
+14 12865 1 6
+14 12865 2 6
+14 12865 3 6
+14 12865 4 6
+14 12865 5 6
+14 6793 1 17
+14 6793 2 17
+14 6793 3 17
+14 6793 4 17
+14 6793 5 17
+14 2973 1 5
+14 2973 2 5
+14 2973 3 5
+14 2973 4 5
+14 2973 5 5
+15 20950 1 7
+15 20950 2 7
+15 20950 3 7
+15 20950 4 7
+15 20950 5 7
+15 4112 1 6
+15 4112 2 6
+15 4112 3 6
+15 4112 4 6
+15 4112 5 6
+15 20069 1 1
+15 20069 2 1
+15 20069 3 1
+15 20069 4 1
+15 20069 5 1
+15 21040 1 17
+15 21040 2 17
+15 21040 3 17
+15 21040 4 17
+15 21040 5 17
+15 1498 1 0
+15 1498 2 0
+15 1498 3 0
+15 1498 4 0
+15 1498 5 0
+15 4453 1 3
+15 4453 2 3
+15 4453 3 3
+15 4453 4 3
+15 4453 5 3
+15 27228 1 17
+15 27228 2 17
+15 27228 3 17
+15 27228 4 17
+15 27228 5 17
+15 9353 1 2
+15 9353 2 2
+15 9353 3 2
+15 9353 4 2
+15 9353 5 2
+15 12060 1 5
+15 12060 2 5
+15 12060 3 5
+15 12060 4 5
+15 12060 5 5
+15 30253 1 15
+15 30253 2 15
+15 30253 3 15
+15 30253 4 15
+15 30253 5 15
+15 9914 1 4
+15 9914 2 4
+15 9914 3 4
+15 9914 4 4
+15 9914 5 4
+15 9111 1 17
+15 9111 2 17
+15 9111 3 17
+15 9111 4 17
+15 9111 5 17
+15 9191 1 13
+15 9191 2 13
+15 9191 3 13
+15 9191 4 13
+15 9191 5 13
+15 2061 1 15
+15 2061 2 15
+15 2061 3 15
+15 2061 4 15
+15 2061 5 15
+15 16458 1 7
+15 16458 2 7
+15 16458 3 7
+15 16458 4 7
+15 16458 5 7
+15 14420 1 17
+15 14420 2 17
+15 14420 3 17
+15 14420 4 17
+15 14420 5 17
+15 11687 1 4
+15 11687 2 4
+15 11687 3 4
+15 11687 4 4
+15 11687 5 4
+15 12915 1 14
+15 12915 2 14
+15 12915 3 14
+15 12915 4 14
+15 12915 5 14
+15 30014 1 5
+15 30014 2 5
+15 30014 3 5
+15 30014 4 5
+15 30014 5 5
+15 17852 1 8
+15 17852 2 8
+15 17852 3 8
+15 17852 4 8
+15 17852 5 8
+15 18801 1 1
+15 18801 2 1
+15 18801 3 1
+15 18801 4 1
+15 18801 5 1
+15 30476 1 10
+15 30476 2 10
+15 30476 3 10
+15 30476 4 10
+15 30476 5 10
+15 19880 1 10
+15 19880 2 10
+15 19880 3 10
+15 19880 4 10
+15 19880 5 10
+15 25937 1 13
+15 25937 2 13
+15 25937 3 13
+15 25937 4 13
+15 25937 5 13
+15 30840 1 17
+15 30840 2 17
+15 30840 3 17
+15 30840 4 17
+15 30840 5 17
+15 29260 1 4
+15 29260 2 4
+15 29260 3 4
+15 29260 4 4
+15 29260 5 4
+15 29698 1 3
+15 29698 2 3
+15 29698 3 3
+15 29698 4 3
+15 29698 5 3
+15 13207 1 12
+15 13207 2 12
+15 13207 3 12
+15 13207 4 12
+15 13207 5 12
+15 8345 1 15
+15 8345 2 15
+15 8345 3 15
+15 8345 4 15
+15 8345 5 15
+15 28649 1 0
+15 28649 2 0
+15 28649 3 0
+15 28649 4 0
+15 28649 5 0
+15 7591 1 3
+15 7591 2 3
+15 7591 3 3
+15 7591 4 3
+15 7591 5 3
+15 11417 1 4
+15 11417 2 4
+15 11417 3 4
+15 11417 4 4
+15 11417 5 4
+15 31952 1 3
+15 31952 2 3
+15 31952 3 3
+15 31952 4 3
+15 31952 5 3
+15 3936 1 5
+15 3936 2 5
+15 3936 3 5
+15 3936 4 5
+15 3936 5 5
+15 855 1 5
+15 855 2 5
+15 855 3 5
+15 855 4 5
+15 855 5 5
+15 6242 1 15
+15 6242 2 15
+15 6242 3 15
+15 6242 4 15
+15 6242 5 15
+15 7617 1 5
+15 7617 2 5
+15 7617 3 5
+15 7617 4 5
+15 7617 5 5
+15 30831 1 12
+15 30831 2 12
+15 30831 3 12
+15 30831 4 12
+15 30831 5 12
+15 27063 1 4
+15 27063 2 4
+15 27063 3 4
+15 27063 4 4
+15 27063 5 4
+15 1925 1 15
+15 1925 2 15
+15 1925 3 15
+15 1925 4 15
+15 1925 5 15
+15 31280 1 0
+15 31280 2 0
+15 31280 3 0
+15 31280 4 0
+15 31280 5 0
+15 8089 1 2
+15 8089 2 2
+15 8089 3 2
+15 8089 4 2
+15 8089 5 2
+15 14799 1 13
+15 14799 2 13
+15 14799 3 13
+15 14799 4 13
+15 14799 5 13
+15 24470 1 3
+15 24470 2 3
+15 24470 3 3
+15 24470 4 3
+15 24470 5 3
+15 3977 1 13
+15 3977 2 13
+15 3977 3 13
+15 3977 4 13
+15 3977 5 13
+15 6822 1 3
+15 6822 2 3
+15 6822 3 3
+15 6822 4 3
+15 6822 5 3
+15 10634 1 1
+15 10634 2 1
+15 10634 3 1
+15 10634 4 1
+15 10634 5 1
+15 30639 1 3
+15 30639 2 3
+15 30639 3 3
+15 30639 4 3
+15 30639 5 3
+15 4697 1 3
+15 4697 2 3
+15 4697 3 3
+15 4697 4 3
+15 4697 5 3
+15 1311 1 1
+15 1311 2 1
+15 1311 3 1
+15 1311 4 1
+15 1311 5 1
+15 29753 1 6
+15 29753 2 6
+15 29753 3 6
+15 29753 4 6
+15 29753 5 6
+15 17644 1 14
+15 17644 2 14
+15 17644 3 14
+15 17644 4 14
+15 17644 5 14
+15 11986 1 9
+15 11986 2 9
+15 11986 3 9
+15 11986 4 9
+15 11986 5 9
+15 29910 1 0
+15 29910 2 0
+15 29910 3 0
+15 29910 4 0
+15 29910 5 0
+15 8977 1 9
+15 8977 2 9
+15 8977 3 9
+15 8977 4 9
+15 8977 5 9
+15 5871 1 1
+15 5871 2 1
+15 5871 3 1
+15 5871 4 1
+15 5871 5 1
+15 22859 1 6
+15 22859 2 6
+15 22859 3 6
+15 22859 4 6
+15 22859 5 6
+15 32348 1 5
+15 32348 2 5
+15 32348 3 5
+15 32348 4 5
+15 32348 5 5
+15 26024 1 2
+15 26024 2 2
+15 26024 3 2
+15 26024 4 2
+15 26024 5 2
+15 25693 1 0
+15 25693 2 0
+15 25693 3 0
+15 25693 4 0
+15 25693 5 0
+15 11966 1 4
+15 11966 2 4
+15 11966 3 4
+15 11966 4 4
+15 11966 5 4
+15 18826 1 14
+15 18826 2 14
+15 18826 3 14
+15 18826 4 14
+15 18826 5 14
+15 31356 1 10
+15 31356 2 10
+15 31356 3 10
+15 31356 4 10
+15 31356 5 10
+15 10078 1 14
+15 10078 2 14
+15 10078 3 14
+15 10078 4 14
+15 10078 5 14
+16 58244 1 14
+16 58244 2 14
+16 58244 3 14
+16 58244 4 14
+16 58244 5 14
+16 25812 1 9
+16 25812 2 9
+16 25812 3 9
+16 25812 4 9
+16 25812 5 9
+16 5981 1 6
+16 5981 2 6
+16 5981 3 6
+16 5981 4 6
+16 5981 5 6
+16 38854 1 14
+16 38854 2 14
+16 38854 3 14
+16 38854 4 14
+16 38854 5 14
+16 29656 1 15
+16 29656 2 15
+16 29656 3 15
+16 29656 4 15
+16 29656 5 15
+16 50754 1 13
+16 50754 2 13
+16 50754 3 13
+16 50754 4 13
+16 50754 5 13
+16 5784 1 13
+16 5784 2 13
+16 5784 3 13
+16 5784 4 13
+16 5784 5 13
+16 61887 1 13
+16 61887 2 13
+16 61887 3 13
+16 61887 4 13
+16 61887 5 13
+16 48214 1 9
+16 48214 2 9
+16 48214 3 9
+16 48214 4 9
+16 48214 5 9
+16 12266 1 2
+16 12266 2 2
+16 12266 3 2
+16 12266 4 2
+16 12266 5 2
+16 38129 1 5
+16 38129 2 5
+16 38129 3 5
+16 38129 4 5
+16 38129 5 5
+16 28380 1 6
+16 28380 2 6
+16 28380 3 6
+16 28380 4 6
+16 28380 5 6
+16 50376 1 1
+16 50376 2 1
+16 50376 3 1
+16 50376 4 1
+16 50376 5 1
+16 51343 1 3
+16 51343 2 3
+16 51343 3 3
+16 51343 4 3
+16 51343 5 3
+16 10060 1 13
+16 10060 2 13
+16 10060 3 13
+16 10060 4 13
+16 10060 5 13
+16 6542 1 2
+16 6542 2 2
+16 6542 3 2
+16 6542 4 2
+16 6542 5 2
+16 9936 1 8
+16 9936 2 8
+16 9936 3 8
+16 9936 4 8
+16 9936 5 8
+16 52971 1 15
+16 52971 2 15
+16 52971 3 15
+16 52971 4 15
+16 52971 5 15
+16 48546 1 12
+16 48546 2 12
+16 48546 3 12
+16 48546 4 12
+16 48546 5 12
+16 8054 1 2
+16 8054 2 2
+16 8054 3 2
+16 8054 4 2
+16 8054 5 2
+16 62559 1 15
+16 62559 2 15
+16 62559 3 15
+16 62559 4 15
+16 62559 5 15
+16 9259 1 14
+16 9259 2 14
+16 9259 3 14
+16 9259 4 14
+16 9259 5 14
+16 29059 1 3
+16 29059 2 3
+16 29059 3 3
+16 29059 4 3
+16 29059 5 3
+16 33772 1 5
+16 33772 2 5
+16 33772 3 5
+16 33772 4 5
+16 33772 5 5
+16 60991 1 6
+16 60991 2 6
+16 60991 3 6
+16 60991 4 6
+16 60991 5 6
+16 42607 1 3
+16 42607 2 3
+16 42607 3 3
+16 42607 4 3
+16 42607 5 3
+16 42127 1 13
+16 42127 2 13
+16 42127 3 13
+16 42127 4 13
+16 42127 5 13
+16 41593 1 7
+16 41593 2 7
+16 41593 3 7
+16 41593 4 7
+16 41593 5 7
+16 2699 1 1
+16 2699 2 1
+16 2699 3 1
+16 2699 4 1
+16 2699 5 1
+16 23372 1 17
+16 23372 2 17
+16 23372 3 17
+16 23372 4 17
+16 23372 5 17
+16 28412 1 9
+16 28412 2 9
+16 28412 3 9
+16 28412 4 9
+16 28412 5 9
+16 33117 1 14
+16 33117 2 14
+16 33117 3 14
+16 33117 4 14
+16 33117 5 14
+16 19250 1 13
+16 19250 2 13
+16 19250 3 13
+16 19250 4 13
+16 19250 5 13
+16 27209 1 7
+16 27209 2 7
+16 27209 3 7
+16 27209 4 7
+16 27209 5 7
+16 24083 1 8
+16 24083 2 8
+16 24083 3 8
+16 24083 4 8
+16 24083 5 8
+16 62474 1 3
+16 62474 2 3
+16 62474 3 3
+16 62474 4 3
+16 62474 5 3
+16 58487 1 15
+16 58487 2 15
+16 58487 3 15
+16 58487 4 15
+16 58487 5 15
+16 59237 1 2
+16 59237 2 2
+16 59237 3 2
+16 59237 4 2
+16 59237 5 2
+16 33459 1 4
+16 33459 2 4
+16 33459 3 4
+16 33459 4 4
+16 33459 5 4
+16 36262 1 13
+16 36262 2 13
+16 36262 3 13
+16 36262 4 13
+16 36262 5 13
+16 45939 1 8
+16 45939 2 8
+16 45939 3 8
+16 45939 4 8
+16 45939 5 8
+16 28047 1 17
+16 28047 2 17
+16 28047 3 17
+16 28047 4 17
+16 28047 5 17
+16 53197 1 5
+16 53197 2 5
+16 53197 3 5
+16 53197 4 5
+16 53197 5 5
+16 25485 1 17
+16 25485 2 17
+16 25485 3 17
+16 25485 4 17
+16 25485 5 17
+16 1170 1 7
+16 1170 2 7
+16 1170 3 7
+16 1170 4 7
+16 1170 5 7
+16 35117 1 0
+16 35117 2 0
+16 35117 3 0
+16 35117 4 0
+16 35117 5 0
+16 51430 1 3
+16 51430 2 3
+16 51430 3 3
+16 51430 4 3
+16 51430 5 3
+16 40909 1 8
+16 40909 2 8
+16 40909 3 8
+16 40909 4 8
+16 40909 5 8
+16 43538 1 7
+16 43538 2 7
+16 43538 3 7
+16 43538 4 7
+16 43538 5 7
+16 62102 1 14
+16 62102 2 14
+16 62102 3 14
+16 62102 4 14
+16 62102 5 14
+16 32920 1 17
+16 32920 2 17
+16 32920 3 17
+16 32920 4 17
+16 32920 5 17
+16 58281 1 15
+16 58281 2 15
+16 58281 3 15
+16 58281 4 15
+16 58281 5 15
+16 25223 1 8
+16 25223 2 8
+16 25223 3 8
+16 25223 4 8
+16 25223 5 8
+16 39064 1 6
+16 39064 2 6
+16 39064 3 6
+16 39064 4 6
+16 39064 5 6
+16 59153 1 3
+16 59153 2 3
+16 59153 3 3
+16 59153 4 3
+16 59153 5 3
+16 31255 1 15
+16 31255 2 15
+16 31255 3 15
+16 31255 4 15
+16 31255 5 15
+16 36698 1 15
+16 36698 2 15
+16 36698 3 15
+16 36698 4 15
+16 36698 5 15
+16 31474 1 2
+16 31474 2 2
+16 31474 3 2
+16 31474 4 2
+16 31474 5 2
+16 26770 1 13
+16 26770 2 13
+16 26770 3 13
+16 26770 4 13
+16 26770 5 13
+16 23106 1 9
+16 23106 2 9
+16 23106 3 9
+16 23106 4 9
+16 23106 5 9
+16 15173 1 1
+16 15173 2 1
+16 15173 3 1
+16 15173 4 1
+16 15173 5 1
+16 21723 1 0
+16 21723 2 0
+16 21723 3 0
+16 21723 4 0
+16 21723 5 0
+16 56305 1 3
+16 56305 2 3
+16 56305 3 3
+16 56305 4 3
+16 56305 5 3
+16 64008 1 14
+16 64008 2 14
+16 64008 3 14
+16 64008 4 14
+16 64008 5 14
+17 93272 1 6
+17 93272 2 6
+17 93272 3 6
+17 93272 4 6
+17 93272 5 6
+17 11659 1 4
+17 11659 2 4
+17 11659 3 4
+17 11659 4 4
+17 11659 5 4
+17 96311 1 5
+17 96311 2 5
+17 96311 3 5
+17 96311 4 5
+17 96311 5 5
+17 63681 1 7
+17 63681 2 7
+17 63681 3 7
+17 63681 4 7
+17 63681 5 7
+17 80799 1 6
+17 80799 2 6
+17 80799 3 6
+17 80799 4 6
+17 80799 5 6
+17 63603 1 1
+17 63603 2 1
+17 63603 3 1
+17 63603 4 1
+17 63603 5 1
+17 112164 1 8
+17 112164 2 8
+17 112164 3 8
+17 112164 4 8
+17 112164 5 8
+17 19891 1 13
+17 19891 2 13
+17 19891 3 13
+17 19891 4 13
+17 19891 5 13
+17 44447 1 5
+17 44447 2 5
+17 44447 3 5
+17 44447 4 5
+17 44447 5 5
+17 71186 1 0
+17 71186 2 0
+17 71186 3 0
+17 71186 4 0
+17 71186 5 0
+17 91697 1 1
+17 91697 2 1
+17 91697 3 1
+17 91697 4 1
+17 91697 5 1
+17 68930 1 7
+17 68930 2 7
+17 68930 3 7
+17 68930 4 7
+17 68930 5 7
+17 22151 1 17
+17 22151 2 17
+17 22151 3 17
+17 22151 4 17
+17 22151 5 17
+17 75004 1 1
+17 75004 2 1
+17 75004 3 1
+17 75004 4 1
+17 75004 5 1
+17 89182 1 8
+17 89182 2 8
+17 89182 3 8
+17 89182 4 8
+17 89182 5 8
+17 14115 1 12
+17 14115 2 12
+17 14115 3 12
+17 14115 4 12
+17 14115 5 12
+17 13641 1 2
+17 13641 2 2
+17 13641 3 2
+17 13641 4 2
+17 13641 5 2
+17 13865 1 1
+17 13865 2 1
+17 13865 3 1
+17 13865 4 1
+17 13865 5 1
+17 81842 1 8
+17 81842 2 8
+17 81842 3 8
+17 81842 4 8
+17 81842 5 8
+17 98226 1 17
+17 98226 2 17
+17 98226 3 17
+17 98226 4 17
+17 98226 5 17
+17 51230 1 3
+17 51230 2 3
+17 51230 3 3
+17 51230 4 3
+17 51230 5 3
+17 13686 1 5
+17 13686 2 5
+17 13686 3 5
+17 13686 4 5
+17 13686 5 5
+17 91828 1 13
+17 91828 2 13
+17 91828 3 13
+17 91828 4 13
+17 91828 5 13
+17 114795 1 13
+17 114795 2 13
+17 114795 3 13
+17 114795 4 13
+17 114795 5 13
+17 12543 1 2
+17 12543 2 2
+17 12543 3 2
+17 12543 4 2
+17 12543 5 2
+17 57890 1 1
+17 57890 2 1
+17 57890 3 1
+17 57890 4 1
+17 57890 5 1
+17 115698 1 13
+17 115698 2 13
+17 115698 3 13
+17 115698 4 13
+17 115698 5 13
+17 63601 1 14
+17 63601 2 14
+17 63601 3 14
+17 63601 4 14
+17 63601 5 14
+17 92716 1 0
+17 92716 2 0
+17 92716 3 0
+17 92716 4 0
+17 92716 5 0
+17 87889 1 13
+17 87889 2 13
+17 87889 3 13
+17 87889 4 13
+17 87889 5 13
+17 123518 1 9
+17 123518 2 9
+17 123518 3 9
+17 123518 4 9
+17 123518 5 9
+17 122122 1 13
+17 122122 2 13
+17 122122 3 13
+17 122122 4 13
+17 122122 5 13
+17 101033 1 7
+17 101033 2 7
+17 101033 3 7
+17 101033 4 7
+17 101033 5 7
+17 9357 1 7
+17 9357 2 7
+17 9357 3 7
+17 9357 4 7
+17 9357 5 7
+17 127595 1 6
+17 127595 2 6
+17 127595 3 6
+17 127595 4 6
+17 127595 5 6
+17 64032 1 2
+17 64032 2 2
+17 64032 3 2
+17 64032 4 2
+17 64032 5 2
+17 72380 1 8
+17 72380 2 8
+17 72380 3 8
+17 72380 4 8
+17 72380 5 8
+17 128576 1 9
+17 128576 2 9
+17 128576 3 9
+17 128576 4 9
+17 128576 5 9
+17 58709 1 14
+17 58709 2 14
+17 58709 3 14
+17 58709 4 14
+17 58709 5 14
+17 90818 1 10
+17 90818 2 10
+17 90818 3 10
+17 90818 4 10
+17 90818 5 10
+17 96369 1 6
+17 96369 2 6
+17 96369 3 6
+17 96369 4 6
+17 96369 5 6
+17 52794 1 2
+17 52794 2 2
+17 52794 3 2
+17 52794 4 2
+17 52794 5 2
+17 105174 1 6
+17 105174 2 6
+17 105174 3 6
+17 105174 4 6
+17 105174 5 6
+17 61857 1 6
+17 61857 2 6
+17 61857 3 6
+17 61857 4 6
+17 61857 5 6
+17 19478 1 3
+17 19478 2 3
+17 19478 3 3
+17 19478 4 3
+17 19478 5 3
+17 117809 1 4
+17 117809 2 4
+17 117809 3 4
+17 117809 4 4
+17 117809 5 4
+17 72978 1 3
+17 72978 2 3
+17 72978 3 3
+17 72978 4 3
+17 72978 5 3
+17 6547 1 0
+17 6547 2 0
+17 6547 3 0
+17 6547 4 0
+17 6547 5 0
+17 68799 1 10
+17 68799 2 10
+17 68799 3 10
+17 68799 4 10
+17 68799 5 10
+17 99900 1 12
+17 99900 2 12
+17 99900 3 12
+17 99900 4 12
+17 99900 5 12
+17 126252 1 12
+17 126252 2 12
+17 126252 3 12
+17 126252 4 12
+17 126252 5 12
+17 83476 1 5
+17 83476 2 5
+17 83476 3 5
+17 83476 4 5
+17 83476 5 5
+17 38083 1 13
+17 38083 2 13
+17 38083 3 13
+17 38083 4 13
+17 38083 5 13
+17 61784 1 13
+17 61784 2 13
+17 61784 3 13
+17 61784 4 13
+17 61784 5 13
+17 24526 1 9
+17 24526 2 9
+17 24526 3 9
+17 24526 4 9
+17 24526 5 9
+17 117696 1 17
+17 117696 2 17
+17 117696 3 17
+17 117696 4 17
+17 117696 5 17
+17 50749 1 10
+17 50749 2 10
+17 50749 3 10
+17 50749 4 10
+17 50749 5 10
+17 55779 1 12
+17 55779 2 12
+17 55779 3 12
+17 55779 4 12
+17 55779 5 12
+17 2470 1 3
+17 2470 2 3
+17 2470 3 3
+17 2470 4 3
+17 2470 5 3
+17 26842 1 2
+17 26842 2 2
+17 26842 3 2
+17 26842 4 2
+17 26842 5 2
+17 16268 1 17
+17 16268 2 17
+17 16268 3 17
+17 16268 4 17
+17 16268 5 17
+17 125988 1 0
+17 125988 2 0
+17 125988 3 0
+17 125988 4 0
+17 125988 5 0
+17 15331 1 1
+17 15331 2 1
+17 15331 3 1
+17 15331 4 1
+17 15331 5 1
+17 87497 1 10
+17 87497 2 10
+17 87497 3 10
+17 87497 4 10
+17 87497 5 10
+18 250333 1 7
+18 250333 2 7
+18 250333 3 7
+18 250333 4 7
+18 250333 5 7
+18 250728 1 3
+18 250728 2 3
+18 250728 3 3
+18 250728 4 3
+18 250728 5 3
+18 218536 1 2
+18 218536 2 2
+18 218536 3 2
+18 218536 4 2
+18 218536 5 2
+18 251345 1 14
+18 251345 2 14
+18 251345 3 14
+18 251345 4 14
+18 251345 5 14
+18 123978 1 2
+18 123978 2 2
+18 123978 3 2
+18 123978 4 2
+18 123978 5 2
+18 25057 1 9
+18 25057 2 9
+18 25057 3 9
+18 25057 4 9
+18 25057 5 9
+18 55168 1 12
+18 55168 2 12
+18 55168 3 12
+18 55168 4 12
+18 55168 5 12
+18 14806 1 10
+18 14806 2 10
+18 14806 3 10
+18 14806 4 10
+18 14806 5 10
+18 252354 1 6
+18 252354 2 6
+18 252354 3 6
+18 252354 4 6
+18 252354 5 6
+18 25497 1 13
+18 25497 2 13
+18 25497 3 13
+18 25497 4 13
+18 25497 5 13
+18 62064 1 15
+18 62064 2 15
+18 62064 3 15
+18 62064 4 15
+18 62064 5 15
+18 209425 1 15
+18 209425 2 15
+18 209425 3 15
+18 209425 4 15
+18 209425 5 15
+18 41291 1 4
+18 41291 2 4
+18 41291 3 4
+18 41291 4 4
+18 41291 5 4
+18 135093 1 5
+18 135093 2 5
+18 135093 3 5
+18 135093 4 5
+18 135093 5 5
+18 245030 1 17
+18 245030 2 17
+18 245030 3 17
+18 245030 4 17
+18 245030 5 17
+18 56931 1 7
+18 56931 2 7
+18 56931 3 7
+18 56931 4 7
+18 56931 5 7
+18 2524 1 8
+18 2524 2 8
+18 2524 3 8
+18 2524 4 8
+18 2524 5 8
+18 196720 1 12
+18 196720 2 12
+18 196720 3 12
+18 196720 4 12
+18 196720 5 12
+18 244100 1 8
+18 244100 2 8
+18 244100 3 8
+18 244100 4 8
+18 244100 5 8
+18 220927 1 0
+18 220927 2 0
+18 220927 3 0
+18 220927 4 0
+18 220927 5 0
+18 216291 1 4
+18 216291 2 4
+18 216291 3 4
+18 216291 4 4
+18 216291 5 4
+18 131478 1 9
+18 131478 2 9
+18 131478 3 9
+18 131478 4 9
+18 131478 5 9
+18 34594 1 13
+18 34594 2 13
+18 34594 3 13
+18 34594 4 13
+18 34594 5 13
+18 199406 1 10
+18 199406 2 10
+18 199406 3 10
+18 199406 4 10
+18 199406 5 10
+18 26816 1 6
+18 26816 2 6
+18 26816 3 6
+18 26816 4 6
+18 26816 5 6
+18 12041 1 8
+18 12041 2 8
+18 12041 3 8
+18 12041 4 8
+18 12041 5 8
+18 91593 1 5
+18 91593 2 5
+18 91593 3 5
+18 91593 4 5
+18 91593 5 5
+18 194186 1 3
+18 194186 2 3
+18 194186 3 3
+18 194186 4 3
+18 194186 5 3
+18 150343 1 2
+18 150343 2 2
+18 150343 3 2
+18 150343 4 2
+18 150343 5 2
+18 222016 1 6
+18 222016 2 6
+18 222016 3 6
+18 222016 4 6
+18 222016 5 6
+18 100345 1 3
+18 100345 2 3
+18 100345 3 3
+18 100345 4 3
+18 100345 5 3
+18 248323 1 17
+18 248323 2 17
+18 248323 3 17
+18 248323 4 17
+18 248323 5 17
+18 248898 1 13
+18 248898 2 13
+18 248898 3 13
+18 248898 4 13
+18 248898 5 13
+18 259523 1 9
+18 259523 2 9
+18 259523 3 9
+18 259523 4 9
+18 259523 5 9
+18 13668 1 12
+18 13668 2 12
+18 13668 3 12
+18 13668 4 12
+18 13668 5 12
+18 190429 1 3
+18 190429 2 3
+18 190429 3 3
+18 190429 4 3
+18 190429 5 3
+18 227309 1 9
+18 227309 2 9
+18 227309 3 9
+18 227309 4 9
+18 227309 5 9
+18 248240 1 10
+18 248240 2 10
+18 248240 3 10
+18 248240 4 10
+18 248240 5 10
+18 179569 1 5
+18 179569 2 5
+18 179569 3 5
+18 179569 4 5
+18 179569 5 5
+18 254832 1 4
+18 254832 2 4
+18 254832 3 4
+18 254832 4 4
+18 254832 5 4
+18 141688 1 9
+18 141688 2 9
+18 141688 3 9
+18 141688 4 9
+18 141688 5 9
+18 44089 1 17
+18 44089 2 17
+18 44089 3 17
+18 44089 4 17
+18 44089 5 17
+18 145850 1 15
+18 145850 2 15
+18 145850 3 15
+18 145850 4 15
+18 145850 5 15
+18 149351 1 1
+18 149351 2 1
+18 149351 3 1
+18 149351 4 1
+18 149351 5 1
+18 161161 1 17
+18 161161 2 17
+18 161161 3 17
+18 161161 4 17
+18 161161 5 17
+18 804 1 10
+18 804 2 10
+18 804 3 10
+18 804 4 10
+18 804 5 10
+18 204942 1 0
+18 204942 2 0
+18 204942 3 0
+18 204942 4 0
+18 204942 5 0
+18 109633 1 10
+18 109633 2 10
+18 109633 3 10
+18 109633 4 10
+18 109633 5 10
+18 189623 1 1
+18 189623 2 1
+18 189623 3 1
+18 189623 4 1
+18 189623 5 1
+18 117578 1 15
+18 117578 2 15
+18 117578 3 15
+18 117578 4 15
+18 117578 5 15
+18 42863 1 13
+18 42863 2 13
+18 42863 3 13
+18 42863 4 13
+18 42863 5 13
+18 138963 1 14
+18 138963 2 14
+18 138963 3 14
+18 138963 4 14
+18 138963 5 14
+18 65040 1 1
+18 65040 2 1
+18 65040 3 1
+18 65040 4 1
+18 65040 5 1
+18 59160 1 4
+18 59160 2 4
+18 59160 3 4
+18 59160 4 4
+18 59160 5 4
+18 128405 1 5
+18 128405 2 5
+18 128405 3 5
+18 128405 4 5
+18 128405 5 5
+18 186053 1 12
+18 186053 2 12
+18 186053 3 12
+18 186053 4 12
+18 186053 5 12
+18 205204 1 2
+18 205204 2 2
+18 205204 3 2
+18 205204 4 2
+18 205204 5 2
+18 179473 1 4
+18 179473 2 4
+18 179473 3 4
+18 179473 4 4
+18 179473 5 4
+18 206442 1 2
+18 206442 2 2
+18 206442 3 2
+18 206442 4 2
+18 206442 5 2
+18 81168 1 5
+18 81168 2 5
+18 81168 3 5
+18 81168 4 5
+18 81168 5 5
+18 209591 1 3
+18 209591 2 3
+18 209591 3 3
+18 209591 4 3
+18 209591 5 3
+18 9801 1 15
+18 9801 2 15
+18 9801 3 15
+18 9801 4 15
+18 9801 5 15
+18 7180 1 17
+18 7180 2 17
+18 7180 3 17
+18 7180 4 17
+18 7180 5 17
+18 148102 1 7
+18 148102 2 7
+18 148102 3 7
+18 148102 4 7
+18 148102 5 7
+19 285360 1 12
+19 285360 2 12
+19 285360 3 12
+19 285360 4 12
+19 285360 5 12
+19 39966 1 6
+19 39966 2 6
+19 39966 3 6
+19 39966 4 6
+19 39966 5 6
+19 439938 1 15
+19 439938 2 15
+19 439938 3 15
+19 439938 4 15
+19 439938 5 15
+19 276172 1 1
+19 276172 2 1
+19 276172 3 1
+19 276172 4 1
+19 276172 5 1
+19 371729 1 17
+19 371729 2 17
+19 371729 3 17
+19 371729 4 17
+19 371729 5 17
+19 168977 1 4
+19 168977 2 4
+19 168977 3 4
+19 168977 4 4
+19 168977 5 4
+19 161548 1 14
+19 161548 2 14
+19 161548 3 14
+19 161548 4 14
+19 161548 5 14
+19 497098 1 15
+19 497098 2 15
+19 497098 3 15
+19 497098 4 15
+19 497098 5 15
+19 51980 1 4
+19 51980 2 4
+19 51980 3 4
+19 51980 4 4
+19 51980 5 4
+19 84417 1 10
+19 84417 2 10
+19 84417 3 10
+19 84417 4 10
+19 84417 5 10
+19 508848 1 3
+19 508848 2 3
+19 508848 3 3
+19 508848 4 3
+19 508848 5 3
+19 249975 1 10
+19 249975 2 10
+19 249975 3 10
+19 249975 4 10
+19 249975 5 10
+19 471817 1 0
+19 471817 2 0
+19 471817 3 0
+19 471817 4 0
+19 471817 5 0
+19 420898 1 14
+19 420898 2 14
+19 420898 3 14
+19 420898 4 14
+19 420898 5 14
+19 62009 1 6
+19 62009 2 6
+19 62009 3 6
+19 62009 4 6
+19 62009 5 6
+19 261112 1 3
+19 261112 2 3
+19 261112 3 3
+19 261112 4 3
+19 261112 5 3
+19 268374 1 7
+19 268374 2 7
+19 268374 3 7
+19 268374 4 7
+19 268374 5 7
+19 92078 1 15
+19 92078 2 15
+19 92078 3 15
+19 92078 4 15
+19 92078 5 15
+19 146323 1 13
+19 146323 2 13
+19 146323 3 13
+19 146323 4 13
+19 146323 5 13
+19 48955 1 10
+19 48955 2 10
+19 48955 3 10
+19 48955 4 10
+19 48955 5 10
+19 336033 1 0
+19 336033 2 0
+19 336033 3 0
+19 336033 4 0
+19 336033 5 0
+19 4833 1 2
+19 4833 2 2
+19 4833 3 2
+19 4833 4 2
+19 4833 5 2
+19 359506 1 3
+19 359506 2 3
+19 359506 3 3
+19 359506 4 3
+19 359506 5 3
+19 477037 1 7
+19 477037 2 7
+19 477037 3 7
+19 477037 4 7
+19 477037 5 7
+19 109440 1 0
+19 109440 2 0
+19 109440 3 0
+19 109440 4 0
+19 109440 5 0
+19 27324 1 0
+19 27324 2 0
+19 27324 3 0
+19 27324 4 0
+19 27324 5 0
+19 361772 1 15
+19 361772 2 15
+19 361772 3 15
+19 361772 4 15
+19 361772 5 15
+19 150657 1 1
+19 150657 2 1
+19 150657 3 1
+19 150657 4 1
+19 150657 5 1
+19 174825 1 8
+19 174825 2 8
+19 174825 3 8
+19 174825 4 8
+19 174825 5 8
+19 352070 1 12
+19 352070 2 12
+19 352070 3 12
+19 352070 4 12
+19 352070 5 12
+19 195450 1 13
+19 195450 2 13
+19 195450 3 13
+19 195450 4 13
+19 195450 5 13
+19 468400 1 2
+19 468400 2 2
+19 468400 3 2
+19 468400 4 2
+19 468400 5 2
+19 330682 1 10
+19 330682 2 10
+19 330682 3 10
+19 330682 4 10
+19 330682 5 10
+19 45062 1 3
+19 45062 2 3
+19 45062 3 3
+19 45062 4 3
+19 45062 5 3
+19 313788 1 1
+19 313788 2 1
+19 313788 3 1
+19 313788 4 1
+19 313788 5 1
+19 60915 1 2
+19 60915 2 2
+19 60915 3 2
+19 60915 4 2
+19 60915 5 2
+19 44594 1 17
+19 44594 2 17
+19 44594 3 17
+19 44594 4 17
+19 44594 5 17
+19 252043 1 17
+19 252043 2 17
+19 252043 3 17
+19 252043 4 17
+19 252043 5 17
+19 401426 1 17
+19 401426 2 17
+19 401426 3 17
+19 401426 4 17
+19 401426 5 17
+19 243851 1 17
+19 243851 2 17
+19 243851 3 17
+19 243851 4 17
+19 243851 5 17
+19 388726 1 4
+19 388726 2 4
+19 388726 3 4
+19 388726 4 4
+19 388726 5 4
+19 134372 1 14
+19 134372 2 14
+19 134372 3 14
+19 134372 4 14
+19 134372 5 14
+19 263363 1 17
+19 263363 2 17
+19 263363 3 17
+19 263363 4 17
+19 263363 5 17
+19 120186 1 15
+19 120186 2 15
+19 120186 3 15
+19 120186 4 15
+19 120186 5 15
+19 245005 1 6
+19 245005 2 6
+19 245005 3 6
+19 245005 4 6
+19 245005 5 6
+19 345640 1 4
+19 345640 2 4
+19 345640 3 4
+19 345640 4 4
+19 345640 5 4
+19 292026 1 1
+19 292026 2 1
+19 292026 3 1
+19 292026 4 1
+19 292026 5 1
+19 337415 1 14
+19 337415 2 14
+19 337415 3 14
+19 337415 4 14
+19 337415 5 14
+19 18276 1 2
+19 18276 2 2
+19 18276 3 2
+19 18276 4 2
+19 18276 5 2
+19 24304 1 7
+19 24304 2 7
+19 24304 3 7
+19 24304 4 7
+19 24304 5 7
+19 70660 1 1
+19 70660 2 1
+19 70660 3 1
+19 70660 4 1
+19 70660 5 1
+19 426302 1 13
+19 426302 2 13
+19 426302 3 13
+19 426302 4 13
+19 426302 5 13
+19 405580 1 15
+19 405580 2 15
+19 405580 3 15
+19 405580 4 15
+19 405580 5 15
+19 16344 1 6
+19 16344 2 6
+19 16344 3 6
+19 16344 4 6
+19 16344 5 6
+19 486995 1 7
+19 486995 2 7
+19 486995 3 7
+19 486995 4 7
+19 486995 5 7
+19 338030 1 3
+19 338030 2 3
+19 338030 3 3
+19 338030 4 3
+19 338030 5 3
+19 22647 1 17
+19 22647 2 17
+19 22647 3 17
+19 22647 4 17
+19 22647 5 17
+19 400385 1 13
+19 400385 2 13
+19 400385 3 13
+19 400385 4 13
+19 400385 5 13
+19 51070 1 8
+19 51070 2 8
+19 51070 3 8
+19 51070 4 8
+19 51070 5 8
+19 19369 1 14
+19 19369 2 14
+19 19369 3 14
+19 19369 4 14
+19 19369 5 14
+19 407294 1 17
+19 407294 2 17
+19 407294 3 17
+19 407294 4 17
+19 407294 5 17
+19 310674 1 1
+19 310674 2 1
+19 310674 3 1
+19 310674 4 1
+19 310674 5 1
+19 228351 1 6
+19 228351 2 6
+19 228351 3 6
+19 228351 4 6
+19 228351 5 6
+19 302663 1 7
+19 302663 2 7
+19 302663 3 7
+19 302663 4 7
+19 302663 5 7
+20 198355 1 15
+20 198355 2 15
+20 198355 3 15
+20 198355 4 15
+20 198355 5 15
+20 296878 1 2
+20 296878 2 2
+20 296878 3 2
+20 296878 4 2
+20 296878 5 2
+20 760518 1 8
+20 760518 2 8
+20 760518 3 8
+20 760518 4 8
+20 760518 5 8
+20 924592 1 1
+20 924592 2 1
+20 924592 3 1
+20 924592 4 1
+20 924592 5 1
+20 561909 1 14
+20 561909 2 14
+20 561909 3 14
+20 561909 4 14
+20 561909 5 14
+20 364293 1 9
+20 364293 2 9
+20 364293 3 9
+20 364293 4 9
+20 364293 5 9
+20 431304 1 15
+20 431304 2 15
+20 431304 3 15
+20 431304 4 15
+20 431304 5 15
+20 24977 1 2
+20 24977 2 2
+20 24977 3 2
+20 24977 4 2
+20 24977 5 2
+20 98684 1 12
+20 98684 2 12
+20 98684 3 12
+20 98684 4 12
+20 98684 5 12
+20 116875 1 6
+20 116875 2 6
+20 116875 3 6
+20 116875 4 6
+20 116875 5 6
+20 121330 1 14
+20 121330 2 14
+20 121330 3 14
+20 121330 4 14
+20 121330 5 14
+20 977011 1 7
+20 977011 2 7
+20 977011 3 7
+20 977011 4 7
+20 977011 5 7
+20 789443 1 2
+20 789443 2 2
+20 789443 3 2
+20 789443 4 2
+20 789443 5 2
+20 539203 1 5
+20 539203 2 5
+20 539203 3 5
+20 539203 4 5
+20 539203 5 5
+20 981911 1 15
+20 981911 2 15
+20 981911 3 15
+20 981911 4 15
+20 981911 5 15
+20 495588 1 1
+20 495588 2 1
+20 495588 3 1
+20 495588 4 1
+20 495588 5 1
+20 24759 1 2
+20 24759 2 2
+20 24759 3 2
+20 24759 4 2
+20 24759 5 2
+20 355299 1 13
+20 355299 2 13
+20 355299 3 13
+20 355299 4 13
+20 355299 5 13
+20 706015 1 0
+20 706015 2 0
+20 706015 3 0
+20 706015 4 0
+20 706015 5 0
+20 1024100 1 13
+20 1024100 2 13
+20 1024100 3 13
+20 1024100 4 13
+20 1024100 5 13
+20 672600 1 7
+20 672600 2 7
+20 672600 3 7
+20 672600 4 7
+20 672600 5 7
+20 420182 1 8
+20 420182 2 8
+20 420182 3 8
+20 420182 4 8
+20 420182 5 8
+20 149062 1 1
+20 149062 2 1
+20 149062 3 1
+20 149062 4 1
+20 149062 5 1
+20 292328 1 7
+20 292328 2 7
+20 292328 3 7
+20 292328 4 7
+20 292328 5 7
+20 522558 1 2
+20 522558 2 2
+20 522558 3 2
+20 522558 4 2
+20 522558 5 2
+20 628026 1 9
+20 628026 2 9
+20 628026 3 9
+20 628026 4 9
+20 628026 5 9
+20 139803 1 0
+20 139803 2 0
+20 139803 3 0
+20 139803 4 0
+20 139803 5 0
+20 457303 1 1
+20 457303 2 1
+20 457303 3 1
+20 457303 4 1
+20 457303 5 1
+20 559378 1 12
+20 559378 2 12
+20 559378 3 12
+20 559378 4 12
+20 559378 5 12
+20 478051 1 1
+20 478051 2 1
+20 478051 3 1
+20 478051 4 1
+20 478051 5 1
+20 670978 1 5
+20 670978 2 5
+20 670978 3 5
+20 670978 4 5
+20 670978 5 5
+20 782352 1 14
+20 782352 2 14
+20 782352 3 14
+20 782352 4 14
+20 782352 5 14
+20 215312 1 15
+20 215312 2 15
+20 215312 3 15
+20 215312 4 15
+20 215312 5 15
+20 807766 1 13
+20 807766 2 13
+20 807766 3 13
+20 807766 4 13
+20 807766 5 13
+20 1027955 1 17
+20 1027955 2 17
+20 1027955 3 17
+20 1027955 4 17
+20 1027955 5 17
+20 724067 1 1
+20 724067 2 1
+20 724067 3 1
+20 724067 4 1
+20 724067 5 1
+20 179596 1 3
+20 179596 2 3
+20 179596 3 3
+20 179596 4 3
+20 179596 5 3
+20 8911 1 13
+20 8911 2 13
+20 8911 3 13
+20 8911 4 13
+20 8911 5 13
+20 462137 1 1
+20 462137 2 1
+20 462137 3 1
+20 462137 4 1
+20 462137 5 1
+20 451091 1 2
+20 451091 2 2
+20 451091 3 2
+20 451091 4 2
+20 451091 5 2
+20 837481 1 4
+20 837481 2 4
+20 837481 3 4
+20 837481 4 4
+20 837481 5 4
+20 61499 1 12
+20 61499 2 12
+20 61499 3 12
+20 61499 4 12
+20 61499 5 12
+20 64499 1 1
+20 64499 2 1
+20 64499 3 1
+20 64499 4 1
+20 64499 5 1
+20 498651 1 14
+20 498651 2 14
+20 498651 3 14
+20 498651 4 14
+20 498651 5 14
+20 139939 1 7
+20 139939 2 7
+20 139939 3 7
+20 139939 4 7
+20 139939 5 7
+20 1021247 1 13
+20 1021247 2 13
+20 1021247 3 13
+20 1021247 4 13
+20 1021247 5 13
+20 203158 1 4
+20 203158 2 4
+20 203158 3 4
+20 203158 4 4
+20 203158 5 4
+20 165605 1 5
+20 165605 2 5
+20 165605 3 5
+20 165605 4 5
+20 165605 5 5
+20 996551 1 10
+20 996551 2 10
+20 996551 3 10
+20 996551 4 10
+20 996551 5 10
+20 344367 1 1
+20 344367 2 1
+20 344367 3 1
+20 344367 4 1
+20 344367 5 1
+20 471785 1 7
+20 471785 2 7
+20 471785 3 7
+20 471785 4 7
+20 471785 5 7
+20 552276 1 8
+20 552276 2 8
+20 552276 3 8
+20 552276 4 8
+20 552276 5 8
+20 535414 1 7
+20 535414 2 7
+20 535414 3 7
+20 535414 4 7
+20 535414 5 7
+20 850839 1 17
+20 850839 2 17
+20 850839 3 17
+20 850839 4 17
+20 850839 5 17
+20 707079 1 2
+20 707079 2 2
+20 707079 3 2
+20 707079 4 2
+20 707079 5 2
+20 311484 1 2
+20 311484 2 2
+20 311484 3 2
+20 311484 4 2
+20 311484 5 2
+20 682726 1 15
+20 682726 2 15
+20 682726 3 15
+20 682726 4 15
+20 682726 5 15
+20 718518 1 7
+20 718518 2 7
+20 718518 3 7
+20 718518 4 7
+20 718518 5 7
+20 584929 1 15
+20 584929 2 15
+20 584929 3 15
+20 584929 4 15
+20 584929 5 15
+20 496804 1 12
+20 496804 2 12
+20 496804 3 12
+20 496804 4 12
+20 496804 5 12
+20 871520 1 3
+20 871520 2 3
+20 871520 3 3
+20 871520 4 3
+20 871520 5 3
+20 766462 1 3
+20 766462 2 3
+20 766462 3 3
+20 766462 4 3
+20 766462 5 3
+20 547770 1 10
+20 547770 2 10
+20 547770 3 10
+20 547770 4 10
+20 547770 5 10
+20 289035 1 17
+20 289035 2 17
+20 289035 3 17
+20 289035 4 17
+20 289035 5 17
+21 1544102 1 17
+21 1544102 2 17
+21 1544102 3 17
+21 1544102 4 17
+21 1544102 5 17
+21 1921124 1 4
+21 1921124 2 4
+21 1921124 3 4
+21 1921124 4 4
+21 1921124 5 4
+21 1244065 1 6
+21 1244065 2 6
+21 1244065 3 6
+21 1244065 4 6
+21 1244065 5 6
+21 949419 1 15
+21 949419 2 15
+21 949419 3 15
+21 949419 4 15
+21 949419 5 15
+21 809660 1 5
+21 809660 2 5
+21 809660 3 5
+21 809660 4 5
+21 809660 5 5
+21 2081078 1 10
+21 2081078 2 10
+21 2081078 3 10
+21 2081078 4 10
+21 2081078 5 10
+21 1324116 1 15
+21 1324116 2 15
+21 1324116 3 15
+21 1324116 4 15
+21 1324116 5 15
+21 769413 1 8
+21 769413 2 8
+21 769413 3 8
+21 769413 4 8
+21 769413 5 8
+21 1471174 1 1
+21 1471174 2 1
+21 1471174 3 1
+21 1471174 4 1
+21 1471174 5 1
+21 2010804 1 7
+21 2010804 2 7
+21 2010804 3 7
+21 2010804 4 7
+21 2010804 5 7
+21 1616690 1 14
+21 1616690 2 14
+21 1616690 3 14
+21 1616690 4 14
+21 1616690 5 14
+21 1017561 1 9
+21 1017561 2 9
+21 1017561 3 9
+21 1017561 4 9
+21 1017561 5 9
+21 957826 1 0
+21 957826 2 0
+21 957826 3 0
+21 957826 4 0
+21 957826 5 0
+21 562864 1 6
+21 562864 2 6
+21 562864 3 6
+21 562864 4 6
+21 562864 5 6
+21 536746 1 4
+21 536746 2 4
+21 536746 3 4
+21 536746 4 4
+21 536746 5 4
+21 2010490 1 17
+21 2010490 2 17
+21 2010490 3 17
+21 2010490 4 17
+21 2010490 5 17
+21 814896 1 6
+21 814896 2 6
+21 814896 3 6
+21 814896 4 6
+21 814896 5 6
+21 2085665 1 5
+21 2085665 2 5
+21 2085665 3 5
+21 2085665 4 5
+21 2085665 5 5
+21 608239 1 12
+21 608239 2 12
+21 608239 3 12
+21 608239 4 12
+21 608239 5 12
+21 1114271 1 6
+21 1114271 2 6
+21 1114271 3 6
+21 1114271 4 6
+21 1114271 5 6
+21 1578775 1 5
+21 1578775 2 5
+21 1578775 3 5
+21 1578775 4 5
+21 1578775 5 5
+21 293537 1 2
+21 293537 2 2
+21 293537 3 2
+21 293537 4 2
+21 293537 5 2
+21 1260407 1 8
+21 1260407 2 8
+21 1260407 3 8
+21 1260407 4 8
+21 1260407 5 8
+21 569959 1 4
+21 569959 2 4
+21 569959 3 4
+21 569959 4 4
+21 569959 5 4
+21 1653758 1 9
+21 1653758 2 9
+21 1653758 3 9
+21 1653758 4 9
+21 1653758 5 9
+21 643309 1 0
+21 643309 2 0
+21 643309 3 0
+21 643309 4 0
+21 643309 5 0
+21 1982846 1 3
+21 1982846 2 3
+21 1982846 3 3
+21 1982846 4 3
+21 1982846 5 3
+21 1986639 1 17
+21 1986639 2 17
+21 1986639 3 17
+21 1986639 4 17
+21 1986639 5 17
+21 1370291 1 17
+21 1370291 2 17
+21 1370291 3 17
+21 1370291 4 17
+21 1370291 5 17
+21 1656681 1 8
+21 1656681 2 8
+21 1656681 3 8
+21 1656681 4 8
+21 1656681 5 8
+21 241796 1 4
+21 241796 2 4
+21 241796 3 4
+21 241796 4 4
+21 241796 5 4
+21 215997 1 6
+21 215997 2 6
+21 215997 3 6
+21 215997 4 6
+21 215997 5 6
+21 821384 1 17
+21 821384 2 17
+21 821384 3 17
+21 821384 4 17
+21 821384 5 17
+21 331161 1 1
+21 331161 2 1
+21 331161 3 1
+21 331161 4 1
+21 331161 5 1
+21 17355 1 5
+21 17355 2 5
+21 17355 3 5
+21 17355 4 5
+21 17355 5 5
+21 1905273 1 7
+21 1905273 2 7
+21 1905273 3 7
+21 1905273 4 7
+21 1905273 5 7
+21 1045457 1 10
+21 1045457 2 10
+21 1045457 3 10
+21 1045457 4 10
+21 1045457 5 10
+21 799145 1 9
+21 799145 2 9
+21 799145 3 9
+21 799145 4 9
+21 799145 5 9
+21 683994 1 13
+21 683994 2 13
+21 683994 3 13
+21 683994 4 13
+21 683994 5 13
+21 1750830 1 4
+21 1750830 2 4
+21 1750830 3 4
+21 1750830 4 4
+21 1750830 5 4
+21 1346663 1 13
+21 1346663 2 13
+21 1346663 3 13
+21 1346663 4 13
+21 1346663 5 13
+21 1200358 1 6
+21 1200358 2 6
+21 1200358 3 6
+21 1200358 4 6
+21 1200358 5 6
+21 968444 1 4
+21 968444 2 4
+21 968444 3 4
+21 968444 4 4
+21 968444 5 4
+21 469486 1 15
+21 469486 2 15
+21 469486 3 15
+21 469486 4 15
+21 469486 5 15
+21 223784 1 3
+21 223784 2 3
+21 223784 3 3
+21 223784 4 3
+21 223784 5 3
+21 841795 1 4
+21 841795 2 4
+21 841795 3 4
+21 841795 4 4
+21 841795 5 4
+21 290242 1 2
+21 290242 2 2
+21 290242 3 2
+21 290242 4 2
+21 290242 5 2
+21 1704107 1 2
+21 1704107 2 2
+21 1704107 3 2
+21 1704107 4 2
+21 1704107 5 2
+21 1087348 1 9
+21 1087348 2 9
+21 1087348 3 9
+21 1087348 4 9
+21 1087348 5 9
+21 513237 1 2
+21 513237 2 2
+21 513237 3 2
+21 513237 4 2
+21 513237 5 2
+21 761725 1 13
+21 761725 2 13
+21 761725 3 13
+21 761725 4 13
+21 761725 5 13
+21 577471 1 6
+21 577471 2 6
+21 577471 3 6
+21 577471 4 6
+21 577471 5 6
+21 875954 1 9
+21 875954 2 9
+21 875954 3 9
+21 875954 4 9
+21 875954 5 9
+21 283735 1 8
+21 283735 2 8
+21 283735 3 8
+21 283735 4 8
+21 283735 5 8
+21 541381 1 17
+21 541381 2 17
+21 541381 3 17
+21 541381 4 17
+21 541381 5 17
+21 1774181 1 14
+21 1774181 2 14
+21 1774181 3 14
+21 1774181 4 14
+21 1774181 5 14
+21 500169 1 17
+21 500169 2 17
+21 500169 3 17
+21 500169 4 17
+21 500169 5 17
+21 1201575 1 7
+21 1201575 2 7
+21 1201575 3 7
+21 1201575 4 7
+21 1201575 5 7
+21 691701 1 1
+21 691701 2 1
+21 691701 3 1
+21 691701 4 1
+21 691701 5 1
+21 172861 1 4
+21 172861 2 4
+21 172861 3 4
+21 172861 4 4
+21 172861 5 4
+21 544935 1 0
+21 544935 2 0
+21 544935 3 0
+21 544935 4 0
+21 544935 5 0
+21 543047 1 3
+21 543047 2 3
+21 543047 3 3
+21 543047 4 3
+21 543047 5 3
+21 1555372 1 3
+21 1555372 2 3
+21 1555372 3 3
+21 1555372 4 3
+21 1555372 5 3
+21 1754316 1 8
+21 1754316 2 8
+21 1754316 3 8
+21 1754316 4 8
+21 1754316 5 8
+22 1701163 1 15
+22 1701163 2 15
+22 1701163 3 15
+22 1701163 4 15
+22 1701163 5 15
+22 2291265 1 9
+22 2291265 2 9
+22 2291265 3 9
+22 2291265 4 9
+22 2291265 5 9
+22 2939154 1 17
+22 2939154 2 17
+22 2939154 3 17
+22 2939154 4 17
+22 2939154 5 17
+22 874939 1 9
+22 874939 2 9
+22 874939 3 9
+22 874939 4 9
+22 874939 5 9
+22 66406 1 0
+22 66406 2 0
+22 66406 3 0
+22 66406 4 0
+22 66406 5 0
+22 2173604 1 10
+22 2173604 2 10
+22 2173604 3 10
+22 2173604 4 10
+22 2173604 5 10
+22 3888560 1 9
+22 3888560 2 9
+22 3888560 3 9
+22 3888560 4 9
+22 3888560 5 9
+22 633256 1 9
+22 633256 2 9
+22 633256 3 9
+22 633256 4 9
+22 633256 5 9
+22 499433 1 0
+22 499433 2 0
+22 499433 3 0
+22 499433 4 0
+22 499433 5 0
+22 523322 1 9
+22 523322 2 9
+22 523322 3 9
+22 523322 4 9
+22 523322 5 9
+22 3422065 1 9
+22 3422065 2 9
+22 3422065 3 9
+22 3422065 4 9
+22 3422065 5 9
+22 1944488 1 13
+22 1944488 2 13
+22 1944488 3 13
+22 1944488 4 13
+22 1944488 5 13
+22 1501254 1 6
+22 1501254 2 6
+22 1501254 3 6
+22 1501254 4 6
+22 1501254 5 6
+22 3637609 1 9
+22 3637609 2 9
+22 3637609 3 9
+22 3637609 4 9
+22 3637609 5 9
+22 3969393 1 3
+22 3969393 2 3
+22 3969393 3 3
+22 3969393 4 3
+22 3969393 5 3
+22 3757241 1 9
+22 3757241 2 9
+22 3757241 3 9
+22 3757241 4 9
+22 3757241 5 9
+22 541635 1 2
+22 541635 2 2
+22 541635 3 2
+22 541635 4 2
+22 541635 5 2
+22 40295 1 1
+22 40295 2 1
+22 40295 3 1
+22 40295 4 1
+22 40295 5 1
+22 4047297 1 0
+22 4047297 2 0
+22 4047297 3 0
+22 4047297 4 0
+22 4047297 5 0
+22 3989485 1 8
+22 3989485 2 8
+22 3989485 3 8
+22 3989485 4 8
+22 3989485 5 8
+22 4103132 1 10
+22 4103132 2 10
+22 4103132 3 10
+22 4103132 4 10
+22 4103132 5 10
+22 1722049 1 5
+22 1722049 2 5
+22 1722049 3 5
+22 1722049 4 5
+22 1722049 5 5
+22 23525 1 9
+22 23525 2 9
+22 23525 3 9
+22 23525 4 9
+22 23525 5 9
+22 2882794 1 13
+22 2882794 2 13
+22 2882794 3 13
+22 2882794 4 13
+22 2882794 5 13
+22 3503039 1 15
+22 3503039 2 15
+22 3503039 3 15
+22 3503039 4 15
+22 3503039 5 15
+22 597461 1 7
+22 597461 2 7
+22 597461 3 7
+22 597461 4 7
+22 597461 5 7
+22 648021 1 14
+22 648021 2 14
+22 648021 3 14
+22 648021 4 14
+22 648021 5 14
+22 2641512 1 2
+22 2641512 2 2
+22 2641512 3 2
+22 2641512 4 2
+22 2641512 5 2
+22 3131854 1 0
+22 3131854 2 0
+22 3131854 3 0
+22 3131854 4 0
+22 3131854 5 0
+22 3363671 1 9
+22 3363671 2 9
+22 3363671 3 9
+22 3363671 4 9
+22 3363671 5 9
+22 480767 1 0
+22 480767 2 0
+22 480767 3 0
+22 480767 4 0
+22 480767 5 0
+22 866487 1 8
+22 866487 2 8
+22 866487 3 8
+22 866487 4 8
+22 866487 5 8
+22 3197473 1 1
+22 3197473 2 1
+22 3197473 3 1
+22 3197473 4 1
+22 3197473 5 1
+22 1760976 1 2
+22 1760976 2 2
+22 1760976 3 2
+22 1760976 4 2
+22 1760976 5 2
+22 952003 1 4
+22 952003 2 4
+22 952003 3 4
+22 952003 4 4
+22 952003 5 4
+22 458806 1 17
+22 458806 2 17
+22 458806 3 17
+22 458806 4 17
+22 458806 5 17
+22 2642177 1 15
+22 2642177 2 15
+22 2642177 3 15
+22 2642177 4 15
+22 2642177 5 15
+22 3671322 1 10
+22 3671322 2 10
+22 3671322 3 10
+22 3671322 4 10
+22 3671322 5 10
+22 18422 1 12
+22 18422 2 12
+22 18422 3 12
+22 18422 4 12
+22 18422 5 12
+22 4143069 1 0
+22 4143069 2 0
+22 4143069 3 0
+22 4143069 4 0
+22 4143069 5 0
+22 4013422 1 13
+22 4013422 2 13
+22 4013422 3 13
+22 4013422 4 13
+22 4013422 5 13
+22 3026661 1 13
+22 3026661 2 13
+22 3026661 3 13
+22 3026661 4 13
+22 3026661 5 13
+22 1402336 1 5
+22 1402336 2 5
+22 1402336 3 5
+22 1402336 4 5
+22 1402336 5 5
+22 3702708 1 10
+22 3702708 2 10
+22 3702708 3 10
+22 3702708 4 10
+22 3702708 5 10
+22 2069402 1 8
+22 2069402 2 8
+22 2069402 3 8
+22 2069402 4 8
+22 2069402 5 8
+22 1380150 1 15
+22 1380150 2 15
+22 1380150 3 15
+22 1380150 4 15
+22 1380150 5 15
+22 2126142 1 12
+22 2126142 2 12
+22 2126142 3 12
+22 2126142 4 12
+22 2126142 5 12
+22 3380057 1 0
+22 3380057 2 0
+22 3380057 3 0
+22 3380057 4 0
+22 3380057 5 0
+22 814956 1 9
+22 814956 2 9
+22 814956 3 9
+22 814956 4 9
+22 814956 5 9
+22 1055203 1 1
+22 1055203 2 1
+22 1055203 3 1
+22 1055203 4 1
+22 1055203 5 1
+22 940480 1 12
+22 940480 2 12
+22 940480 3 12
+22 940480 4 12
+22 940480 5 12
+22 3647615 1 17
+22 3647615 2 17
+22 3647615 3 17
+22 3647615 4 17
+22 3647615 5 17
+22 3000063 1 6
+22 3000063 2 6
+22 3000063 3 6
+22 3000063 4 6
+22 3000063 5 6
+22 3033624 1 13
+22 3033624 2 13
+22 3033624 3 13
+22 3033624 4 13
+22 3033624 5 13
+22 3135628 1 9
+22 3135628 2 9
+22 3135628 3 9
+22 3135628 4 9
+22 3135628 5 9
+22 1580393 1 1
+22 1580393 2 1
+22 1580393 3 1
+22 1580393 4 1
+22 1580393 5 1
+22 4193568 1 8
+22 4193568 2 8
+22 4193568 3 8
+22 4193568 4 8
+22 4193568 5 8
+22 800980 1 10
+22 800980 2 10
+22 800980 3 10
+22 800980 4 10
+22 800980 5 10
+22 1419961 1 17
+22 1419961 2 17
+22 1419961 3 17
+22 1419961 4 17
+22 1419961 5 17
+22 1144691 1 3
+22 1144691 2 3
+22 1144691 3 3
+22 1144691 4 3
+22 1144691 5 3
+22 2573267 1 8
+22 2573267 2 8
+22 2573267 3 8
+22 2573267 4 8
+22 2573267 5 8
+22 3310445 1 7
+22 3310445 2 7
+22 3310445 3 7
+22 3310445 4 7
+22 3310445 5 7
+22 629717 1 13
+22 629717 2 13
+22 629717 3 13
+22 629717 4 13
+22 629717 5 13
+22 1552778 1 17
+22 1552778 2 17
+22 1552778 3 17
+22 1552778 4 17
+22 1552778 5 17
+23 3046911 1 1
+23 3046911 2 1
+23 3046911 3 1
+23 3046911 4 1
+23 3046911 5 1
+23 769783 1 9
+23 769783 2 9
+23 769783 3 9
+23 769783 4 9
+23 769783 5 9
+23 2374124 1 13
+23 2374124 2 13
+23 2374124 3 13
+23 2374124 4 13
+23 2374124 5 13
+23 2996918 1 15
+23 2996918 2 15
+23 2996918 3 15
+23 2996918 4 15
+23 2996918 5 15
+23 2411310 1 6
+23 2411310 2 6
+23 2411310 3 6
+23 2411310 4 6
+23 2411310 5 6
+23 744660 1 8
+23 744660 2 8
+23 744660 3 8
+23 744660 4 8
+23 744660 5 8
+23 7927100 1 17
+23 7927100 2 17
+23 7927100 3 17
+23 7927100 4 17
+23 7927100 5 17
+23 1377692 1 0
+23 1377692 2 0
+23 1377692 3 0
+23 1377692 4 0
+23 1377692 5 0
+23 2920499 1 4
+23 2920499 2 4
+23 2920499 3 4
+23 2920499 4 4
+23 2920499 5 4
+23 6611555 1 4
+23 6611555 2 4
+23 6611555 3 4
+23 6611555 4 4
+23 6611555 5 4
+23 723122 1 0
+23 723122 2 0
+23 723122 3 0
+23 723122 4 0
+23 723122 5 0
+23 5130765 1 14
+23 5130765 2 14
+23 5130765 3 14
+23 5130765 4 14
+23 5130765 5 14
+23 621060 1 6
+23 621060 2 6
+23 621060 3 6
+23 621060 4 6
+23 621060 5 6
+23 6806998 1 1
+23 6806998 2 1
+23 6806998 3 1
+23 6806998 4 1
+23 6806998 5 1
+23 3524228 1 7
+23 3524228 2 7
+23 3524228 3 7
+23 3524228 4 7
+23 3524228 5 7
+23 1077839 1 1
+23 1077839 2 1
+23 1077839 3 1
+23 1077839 4 1
+23 1077839 5 1
+23 5526077 1 8
+23 5526077 2 8
+23 5526077 3 8
+23 5526077 4 8
+23 5526077 5 8
+23 7013541 1 13
+23 7013541 2 13
+23 7013541 3 13
+23 7013541 4 13
+23 7013541 5 13
+23 4998096 1 9
+23 4998096 2 9
+23 4998096 3 9
+23 4998096 4 9
+23 4998096 5 9
+23 5128233 1 5
+23 5128233 2 5
+23 5128233 3 5
+23 5128233 4 5
+23 5128233 5 5
+23 1863578 1 9
+23 1863578 2 9
+23 1863578 3 9
+23 1863578 4 9
+23 1863578 5 9
+23 6838283 1 17
+23 6838283 2 17
+23 6838283 3 17
+23 6838283 4 17
+23 6838283 5 17
+23 1134869 1 1
+23 1134869 2 1
+23 1134869 3 1
+23 1134869 4 1
+23 1134869 5 1
+23 2111849 1 12
+23 2111849 2 12
+23 2111849 3 12
+23 2111849 4 12
+23 2111849 5 12
+23 1488511 1 9
+23 1488511 2 9
+23 1488511 3 9
+23 1488511 4 9
+23 1488511 5 9
+23 4807048 1 10
+23 4807048 2 10
+23 4807048 3 10
+23 4807048 4 10
+23 4807048 5 10
+23 393912 1 13
+23 393912 2 13
+23 393912 3 13
+23 393912 4 13
+23 393912 5 13
+23 5219424 1 0
+23 5219424 2 0
+23 5219424 3 0
+23 5219424 4 0
+23 5219424 5 0
+23 8137072 1 2
+23 8137072 2 2
+23 8137072 3 2
+23 8137072 4 2
+23 8137072 5 2
+23 5590877 1 1
+23 5590877 2 1
+23 5590877 3 1
+23 5590877 4 1
+23 5590877 5 1
+23 5294465 1 2
+23 5294465 2 2
+23 5294465 3 2
+23 5294465 4 2
+23 5294465 5 2
+23 1348707 1 6
+23 1348707 2 6
+23 1348707 3 6
+23 1348707 4 6
+23 1348707 5 6
+23 7997848 1 6
+23 7997848 2 6
+23 7997848 3 6
+23 7997848 4 6
+23 7997848 5 6
+23 7575827 1 10
+23 7575827 2 10
+23 7575827 3 10
+23 7575827 4 10
+23 7575827 5 10
+23 4135707 1 5
+23 4135707 2 5
+23 4135707 3 5
+23 4135707 4 5
+23 4135707 5 5
+23 5834316 1 0
+23 5834316 2 0
+23 5834316 3 0
+23 5834316 4 0
+23 5834316 5 0
+23 5605190 1 2
+23 5605190 2 2
+23 5605190 3 2
+23 5605190 4 2
+23 5605190 5 2
+23 3412980 1 4
+23 3412980 2 4
+23 3412980 3 4
+23 3412980 4 4
+23 3412980 5 4
+23 2337431 1 10
+23 2337431 2 10
+23 2337431 3 10
+23 2337431 4 10
+23 2337431 5 10
+23 1248504 1 17
+23 1248504 2 17
+23 1248504 3 17
+23 1248504 4 17
+23 1248504 5 17
+23 2425452 1 14
+23 2425452 2 14
+23 2425452 3 14
+23 2425452 4 14
+23 2425452 5 14
+23 5214096 1 6
+23 5214096 2 6
+23 5214096 3 6
+23 5214096 4 6
+23 5214096 5 6
+23 1257705 1 8
+23 1257705 2 8
+23 1257705 3 8
+23 1257705 4 8
+23 1257705 5 8
+23 527815 1 12
+23 527815 2 12
+23 527815 3 12
+23 527815 4 12
+23 527815 5 12
+23 4250399 1 5
+23 4250399 2 5
+23 4250399 3 5
+23 4250399 4 5
+23 4250399 5 5
+23 1200698 1 4
+23 1200698 2 4
+23 1200698 3 4
+23 1200698 4 4
+23 1200698 5 4
+23 4310378 1 8
+23 4310378 2 8
+23 4310378 3 8
+23 4310378 4 8
+23 4310378 5 8
+23 724255 1 6
+23 724255 2 6
+23 724255 3 6
+23 724255 4 6
+23 724255 5 6
+23 5100058 1 9
+23 5100058 2 9
+23 5100058 3 9
+23 5100058 4 9
+23 5100058 5 9
+23 6466953 1 4
+23 6466953 2 4
+23 6466953 3 4
+23 6466953 4 4
+23 6466953 5 4
+23 181844 1 17
+23 181844 2 17
+23 181844 3 17
+23 181844 4 17
+23 181844 5 17
+23 527081 1 15
+23 527081 2 15
+23 527081 3 15
+23 527081 4 15
+23 527081 5 15
+23 194874 1 0
+23 194874 2 0
+23 194874 3 0
+23 194874 4 0
+23 194874 5 0
+23 5612248 1 7
+23 5612248 2 7
+23 5612248 3 7
+23 5612248 4 7
+23 5612248 5 7
+23 2969929 1 15
+23 2969929 2 15
+23 2969929 3 15
+23 2969929 4 15
+23 2969929 5 15
+23 7237394 1 15
+23 7237394 2 15
+23 7237394 3 15
+23 7237394 4 15
+23 7237394 5 15
+23 865283 1 7
+23 865283 2 7
+23 865283 3 7
+23 865283 4 7
+23 865283 5 7
+23 235461 1 3
+23 235461 2 3
+23 235461 3 3
+23 235461 4 3
+23 235461 5 3
+23 6769613 1 0
+23 6769613 2 0
+23 6769613 3 0
+23 6769613 4 0
+23 6769613 5 0
+23 5015052 1 7
+23 5015052 2 7
+23 5015052 3 7
+23 5015052 4 7
+23 5015052 5 7
+23 3295257 1 13
+23 3295257 2 13
+23 3295257 3 13
+23 3295257 4 13
+23 3295257 5 13
+23 989877 1 1
+23 989877 2 1
+23 989877 3 1
+23 989877 4 1
+23 989877 5 1
+23 1637319 1 13
+23 1637319 2 13
+23 1637319 3 13
+23 1637319 4 13
+23 1637319 5 13
+23 3018058 1 13
+23 3018058 2 13
+23 3018058 3 13
+23 3018058 4 13
+23 3018058 5 13
+24 9775649 1 12
+24 9775649 2 12
+24 9775649 3 12
+24 9775649 4 12
+24 9775649 5 12
+24 14133895 1 9
+24 14133895 2 9
+24 14133895 3 9
+24 14133895 4 9
+24 14133895 5 9
+24 3743280 1 17
+24 3743280 2 17
+24 3743280 3 17
+24 3743280 4 17
+24 3743280 5 17
+24 1023898 1 3
+24 1023898 2 3
+24 1023898 3 3
+24 1023898 4 3
+24 1023898 5 3
+24 9941521 1 3
+24 9941521 2 3
+24 9941521 3 3
+24 9941521 4 3
+24 9941521 5 3
+24 10377160 1 3
+24 10377160 2 3
+24 10377160 3 3
+24 10377160 4 3
+24 10377160 5 3
+24 11342584 1 1
+24 11342584 2 1
+24 11342584 3 1
+24 11342584 4 1
+24 11342584 5 1
+24 9294179 1 1
+24 9294179 2 1
+24 9294179 3 1
+24 9294179 4 1
+24 9294179 5 1
+24 15025827 1 9
+24 15025827 2 9
+24 15025827 3 9
+24 15025827 4 9
+24 15025827 5 9
+24 3498285 1 14
+24 3498285 2 14
+24 3498285 3 14
+24 3498285 4 14
+24 3498285 5 14
+24 8199923 1 13
+24 8199923 2 13
+24 8199923 3 13
+24 8199923 4 13
+24 8199923 5 13
+24 90634 1 1
+24 90634 2 1
+24 90634 3 1
+24 90634 4 1
+24 90634 5 1
+24 12997310 1 6
+24 12997310 2 6
+24 12997310 3 6
+24 12997310 4 6
+24 12997310 5 6
+24 14265335 1 17
+24 14265335 2 17
+24 14265335 3 17
+24 14265335 4 17
+24 14265335 5 17
+24 5492707 1 13
+24 5492707 2 13
+24 5492707 3 13
+24 5492707 4 13
+24 5492707 5 13
+24 263738 1 13
+24 263738 2 13
+24 263738 3 13
+24 263738 4 13
+24 263738 5 13
+24 13671070 1 4
+24 13671070 2 4
+24 13671070 3 4
+24 13671070 4 4
+24 13671070 5 4
+24 8325339 1 0
+24 8325339 2 0
+24 8325339 3 0
+24 8325339 4 0
+24 8325339 5 0
+24 9752092 1 8
+24 9752092 2 8
+24 9752092 3 8
+24 9752092 4 8
+24 9752092 5 8
+24 10821970 1 5
+24 10821970 2 5
+24 10821970 3 5
+24 10821970 4 5
+24 10821970 5 5
+24 3248722 1 0
+24 3248722 2 0
+24 3248722 3 0
+24 3248722 4 0
+24 3248722 5 0
+24 11447937 1 12
+24 11447937 2 12
+24 11447937 3 12
+24 11447937 4 12
+24 11447937 5 12
+24 6691593 1 6
+24 6691593 2 6
+24 6691593 3 6
+24 6691593 4 6
+24 6691593 5 6
+24 10840036 1 7
+24 10840036 2 7
+24 10840036 3 7
+24 10840036 4 7
+24 10840036 5 7
+24 8193085 1 3
+24 8193085 2 3
+24 8193085 3 3
+24 8193085 4 3
+24 8193085 5 3
+24 13272070 1 17
+24 13272070 2 17
+24 13272070 3 17
+24 13272070 4 17
+24 13272070 5 17
+24 3317672 1 8
+24 3317672 2 8
+24 3317672 3 8
+24 3317672 4 8
+24 3317672 5 8
+24 9720374 1 6
+24 9720374 2 6
+24 9720374 3 6
+24 9720374 4 6
+24 9720374 5 6
+24 3803032 1 15
+24 3803032 2 15
+24 3803032 3 15
+24 3803032 4 15
+24 3803032 5 15
+24 8338298 1 12
+24 8338298 2 12
+24 8338298 3 12
+24 8338298 4 12
+24 8338298 5 12
+24 8391433 1 8
+24 8391433 2 8
+24 8391433 3 8
+24 8391433 4 8
+24 8391433 5 8
+24 3759812 1 17
+24 3759812 2 17
+24 3759812 3 17
+24 3759812 4 17
+24 3759812 5 17
+24 11028207 1 17
+24 11028207 2 17
+24 11028207 3 17
+24 11028207 4 17
+24 11028207 5 17
+24 7289955 1 15
+24 7289955 2 15
+24 7289955 3 15
+24 7289955 4 15
+24 7289955 5 15
+24 3277010 1 9
+24 3277010 2 9
+24 3277010 3 9
+24 3277010 4 9
+24 3277010 5 9
+24 15934652 1 4
+24 15934652 2 4
+24 15934652 3 4
+24 15934652 4 4
+24 15934652 5 4
+24 7837344 1 0
+24 7837344 2 0
+24 7837344 3 0
+24 7837344 4 0
+24 7837344 5 0
+24 6315577 1 15
+24 6315577 2 15
+24 6315577 3 15
+24 6315577 4 15
+24 6315577 5 15
+24 9738174 1 10
+24 9738174 2 10
+24 9738174 3 10
+24 9738174 4 10
+24 9738174 5 10
+24 16135808 1 4
+24 16135808 2 4
+24 16135808 3 4
+24 16135808 4 4
+24 16135808 5 4
+24 7068511 1 10
+24 7068511 2 10
+24 7068511 3 10
+24 7068511 4 10
+24 7068511 5 10
+24 7762664 1 5
+24 7762664 2 5
+24 7762664 3 5
+24 7762664 4 5
+24 7762664 5 5
+24 13117465 1 10
+24 13117465 2 10
+24 13117465 3 10
+24 13117465 4 10
+24 13117465 5 10
+24 9819176 1 9
+24 9819176 2 9
+24 9819176 3 9
+24 9819176 4 9
+24 9819176 5 9
+24 2572469 1 1
+24 2572469 2 1
+24 2572469 3 1
+24 2572469 4 1
+24 2572469 5 1
+24 4497745 1 1
+24 4497745 2 1
+24 4497745 3 1
+24 4497745 4 1
+24 4497745 5 1
+24 6842950 1 0
+24 6842950 2 0
+24 6842950 3 0
+24 6842950 4 0
+24 6842950 5 0
+24 28157 1 14
+24 28157 2 14
+24 28157 3 14
+24 28157 4 14
+24 28157 5 14
+24 9748348 1 15
+24 9748348 2 15
+24 9748348 3 15
+24 9748348 4 15
+24 9748348 5 15
+24 12554184 1 8
+24 12554184 2 8
+24 12554184 3 8
+24 12554184 4 8
+24 12554184 5 8
+24 8971577 1 4
+24 8971577 2 4
+24 8971577 3 4
+24 8971577 4 4
+24 8971577 5 4
+24 1701631 1 9
+24 1701631 2 9
+24 1701631 3 9
+24 1701631 4 9
+24 1701631 5 9
+24 11334757 1 6
+24 11334757 2 6
+24 11334757 3 6
+24 11334757 4 6
+24 11334757 5 6
+24 5922455 1 10
+24 5922455 2 10
+24 5922455 3 10
+24 5922455 4 10
+24 5922455 5 10
+24 6335742 1 7
+24 6335742 2 7
+24 6335742 3 7
+24 6335742 4 7
+24 6335742 5 7
+24 6162272 1 6
+24 6162272 2 6
+24 6162272 3 6
+24 6162272 4 6
+24 6162272 5 6
+24 9389682 1 3
+24 9389682 2 3
+24 9389682 3 3
+24 9389682 4 3
+24 9389682 5 3
+24 14185082 1 9
+24 14185082 2 9
+24 14185082 3 9
+24 14185082 4 9
+24 14185082 5 9
+24 4157744 1 1
+24 4157744 2 1
+24 4157744 3 1
+24 4157744 4 1
+24 4157744 5 1
+24 15978247 1 6
+24 15978247 2 6
+24 15978247 3 6
+24 15978247 4 6
+24 15978247 5 6
+24 2710908 1 7
+24 2710908 2 7
+24 2710908 3 7
+24 2710908 4 7
+24 2710908 5 7
+24 10358562 1 5
+24 10358562 2 5
+24 10358562 3 5
+24 10358562 4 5
+24 10358562 5 5
+24 10869634 1 15
+24 10869634 2 15
+24 10869634 3 15
+24 10869634 4 15
+24 10869634 5 15
+24 6150158 1 17
+24 6150158 2 17
+24 6150158 3 17
+24 6150158 4 17
+24 6150158 5 17
+25 27898613 1 5
+25 27898613 2 5
+25 27898613 3 5
+25 27898613 4 5
+25 27898613 5 5
+25 29501 1 1
+25 29501 2 1
+25 29501 3 1
+25 29501 4 1
+25 29501 5 1
+25 15761162 1 8
+25 15761162 2 8
+25 15761162 3 8
+25 15761162 4 8
+25 15761162 5 8
+25 15728788 1 14
+25 15728788 2 14
+25 15728788 3 14
+25 15728788 4 14
+25 15728788 5 14
+25 33257945 1 14
+25 33257945 2 14
+25 33257945 3 14
+25 33257945 4 14
+25 33257945 5 14
+25 25725432 1 1
+25 25725432 2 1
+25 25725432 3 1
+25 25725432 4 1
+25 25725432 5 1
+25 32158340 1 4
+25 32158340 2 4
+25 32158340 3 4
+25 32158340 4 4
+25 32158340 5 4
+25 14232919 1 6
+25 14232919 2 6
+25 14232919 3 6
+25 14232919 4 6
+25 14232919 5 6
+25 25835501 1 6
+25 25835501 2 6
+25 25835501 3 6
+25 25835501 4 6
+25 25835501 5 6
+25 17975125 1 17
+25 17975125 2 17
+25 17975125 3 17
+25 17975125 4 17
+25 17975125 5 17
+25 1306676 1 9
+25 1306676 2 9
+25 1306676 3 9
+25 1306676 4 9
+25 1306676 5 9
+25 15859824 1 7
+25 15859824 2 7
+25 15859824 3 7
+25 15859824 4 7
+25 15859824 5 7
+25 28894333 1 4
+25 28894333 2 4
+25 28894333 3 4
+25 28894333 4 4
+25 28894333 5 4
+25 9046116 1 15
+25 9046116 2 15
+25 9046116 3 15
+25 9046116 4 15
+25 9046116 5 15
+25 26019062 1 13
+25 26019062 2 13
+25 26019062 3 13
+25 26019062 4 13
+25 26019062 5 13
+25 1778640 1 9
+25 1778640 2 9
+25 1778640 3 9
+25 1778640 4 9
+25 1778640 5 9
+25 10266904 1 1
+25 10266904 2 1
+25 10266904 3 1
+25 10266904 4 1
+25 10266904 5 1
+25 6909977 1 3
+25 6909977 2 3
+25 6909977 3 3
+25 6909977 4 3
+25 6909977 5 3
+25 10702892 1 2
+25 10702892 2 2
+25 10702892 3 2
+25 10702892 4 2
+25 10702892 5 2
+25 11960717 1 6
+25 11960717 2 6
+25 11960717 3 6
+25 11960717 4 6
+25 11960717 5 6
+25 5203472 1 1
+25 5203472 2 1
+25 5203472 3 1
+25 5203472 4 1
+25 5203472 5 1
+25 29147083 1 17
+25 29147083 2 17
+25 29147083 3 17
+25 29147083 4 17
+25 29147083 5 17
+25 24580154 1 6
+25 24580154 2 6
+25 24580154 3 6
+25 24580154 4 6
+25 24580154 5 6
+25 14263395 1 8
+25 14263395 2 8
+25 14263395 3 8
+25 14263395 4 8
+25 14263395 5 8
+25 22955773 1 7
+25 22955773 2 7
+25 22955773 3 7
+25 22955773 4 7
+25 22955773 5 7
+25 21675961 1 8
+25 21675961 2 8
+25 21675961 3 8
+25 21675961 4 8
+25 21675961 5 8
+25 7257867 1 8
+25 7257867 2 8
+25 7257867 3 8
+25 7257867 4 8
+25 7257867 5 8
+25 20686894 1 5
+25 20686894 2 5
+25 20686894 3 5
+25 20686894 4 5
+25 20686894 5 5
+25 29779770 1 0
+25 29779770 2 0
+25 29779770 3 0
+25 29779770 4 0
+25 29779770 5 0
+25 27342720 1 8
+25 27342720 2 8
+25 27342720 3 8
+25 27342720 4 8
+25 27342720 5 8
+25 622218 1 9
+25 622218 2 9
+25 622218 3 9
+25 622218 4 9
+25 622218 5 9
+25 12630641 1 8
+25 12630641 2 8
+25 12630641 3 8
+25 12630641 4 8
+25 12630641 5 8
+25 3245670 1 0
+25 3245670 2 0
+25 3245670 3 0
+25 3245670 4 0
+25 3245670 5 0
+25 521894 1 8
+25 521894 2 8
+25 521894 3 8
+25 521894 4 8
+25 521894 5 8
+25 14849322 1 2
+25 14849322 2 2
+25 14849322 3 2
+25 14849322 4 2
+25 14849322 5 2
+25 12921554 1 8
+25 12921554 2 8
+25 12921554 3 8
+25 12921554 4 8
+25 12921554 5 8
+25 23383269 1 3
+25 23383269 2 3
+25 23383269 3 3
+25 23383269 4 3
+25 23383269 5 3
+25 10251539 1 2
+25 10251539 2 2
+25 10251539 3 2
+25 10251539 4 2
+25 10251539 5 2
+25 16251487 1 14
+25 16251487 2 14
+25 16251487 3 14
+25 16251487 4 14
+25 16251487 5 14
+25 9046939 1 3
+25 9046939 2 3
+25 9046939 3 3
+25 9046939 4 3
+25 9046939 5 3
+25 1286237 1 10
+25 1286237 2 10
+25 1286237 3 10
+25 1286237 4 10
+25 1286237 5 10
+25 1561491 1 6
+25 1561491 2 6
+25 1561491 3 6
+25 1561491 4 6
+25 1561491 5 6
+25 25555747 1 2
+25 25555747 2 2
+25 25555747 3 2
+25 25555747 4 2
+25 25555747 5 2
+25 6644283 1 17
+25 6644283 2 17
+25 6644283 3 17
+25 6644283 4 17
+25 6644283 5 17
+25 25724985 1 6
+25 25724985 2 6
+25 25724985 3 6
+25 25724985 4 6
+25 25724985 5 6
+25 123989 1 14
+25 123989 2 14
+25 123989 3 14
+25 123989 4 14
+25 123989 5 14
+25 17415794 1 7
+25 17415794 2 7
+25 17415794 3 7
+25 17415794 4 7
+25 17415794 5 7
+25 26732483 1 12
+25 26732483 2 12
+25 26732483 3 12
+25 26732483 4 12
+25 26732483 5 12
+25 30810665 1 14
+25 30810665 2 14
+25 30810665 3 14
+25 30810665 4 14
+25 30810665 5 14
+25 5383023 1 6
+25 5383023 2 6
+25 5383023 3 6
+25 5383023 4 6
+25 5383023 5 6
+25 20795854 1 1
+25 20795854 2 1
+25 20795854 3 1
+25 20795854 4 1
+25 20795854 5 1
+25 32135530 1 6
+25 32135530 2 6
+25 32135530 3 6
+25 32135530 4 6
+25 32135530 5 6
+25 8529568 1 15
+25 8529568 2 15
+25 8529568 3 15
+25 8529568 4 15
+25 8529568 5 15
+25 29472599 1 15
+25 29472599 2 15
+25 29472599 3 15
+25 29472599 4 15
+25 29472599 5 15
+25 18752955 1 7
+25 18752955 2 7
+25 18752955 3 7
+25 18752955 4 7
+25 18752955 5 7
+25 7624970 1 12
+25 7624970 2 12
+25 7624970 3 12
+25 7624970 4 12
+25 7624970 5 12
+25 14450005 1 17
+25 14450005 2 17
+25 14450005 3 17
+25 14450005 4 17
+25 14450005 5 17
+25 5230955 1 1
+25 5230955 2 1
+25 5230955 3 1
+25 5230955 4 1
+25 5230955 5 1
+25 22090308 1 5
+25 22090308 2 5
+25 22090308 3 5
+25 22090308 4 5
+25 22090308 5 5
+25 19848608 1 9
+25 19848608 2 9
+25 19848608 3 9
+25 19848608 4 9
+25 19848608 5 9
+25 24404419 1 6
+25 24404419 2 6
+25 24404419 3 6
+25 24404419 4 6
+25 24404419 5 6
+25 29009514 1 14
+25 29009514 2 14
+25 29009514 3 14
+25 29009514 4 14
+25 29009514 5 14
+25 24460148 1 6
+25 24460148 2 6
+25 24460148 3 6
+25 24460148 4 6
+25 24460148 5 6
+25 20198351 1 10
+25 20198351 2 10
+25 20198351 3 10
+25 20198351 4 10
+25 20198351 5 10
+26 7084154 1 9
+26 7084154 2 9
+26 7084154 3 9
+26 7084154 4 9
+26 7084154 5 9
+26 25565466 1 9
+26 25565466 2 9
+26 25565466 3 9
+26 25565466 4 9
+26 25565466 5 9
+26 46816379 1 15
+26 46816379 2 15
+26 46816379 3 15
+26 46816379 4 15
+26 46816379 5 15
+26 21945765 1 1
+26 21945765 2 1
+26 21945765 3 1
+26 21945765 4 1
+26 21945765 5 1
+26 13640323 1 17
+26 13640323 2 17
+26 13640323 3 17
+26 13640323 4 17
+26 13640323 5 17
+26 30012262 1 13
+26 30012262 2 13
+26 30012262 3 13
+26 30012262 4 13
+26 30012262 5 13
+26 20042720 1 5
+26 20042720 2 5
+26 20042720 3 5
+26 20042720 4 5
+26 20042720 5 5
+26 16193914 1 6
+26 16193914 2 6
+26 16193914 3 6
+26 16193914 4 6
+26 16193914 5 6
+26 10183696 1 4
+26 10183696 2 4
+26 10183696 3 4
+26 10183696 4 4
+26 10183696 5 4
+26 24876252 1 0
+26 24876252 2 0
+26 24876252 3 0
+26 24876252 4 0
+26 24876252 5 0
+26 5209203 1 13
+26 5209203 2 13
+26 5209203 3 13
+26 5209203 4 13
+26 5209203 5 13
+26 18883903 1 17
+26 18883903 2 17
+26 18883903 3 17
+26 18883903 4 17
+26 18883903 5 17
+26 48312129 1 5
+26 48312129 2 5
+26 48312129 3 5
+26 48312129 4 5
+26 48312129 5 5
+26 24703773 1 7
+26 24703773 2 7
+26 24703773 3 7
+26 24703773 4 7
+26 24703773 5 7
+26 65103293 1 2
+26 65103293 2 2
+26 65103293 3 2
+26 65103293 4 2
+26 65103293 5 2
+26 64342799 1 8
+26 64342799 2 8
+26 64342799 3 8
+26 64342799 4 8
+26 64342799 5 8
+26 54033834 1 10
+26 54033834 2 10
+26 54033834 3 10
+26 54033834 4 10
+26 54033834 5 10
+26 11156063 1 17
+26 11156063 2 17
+26 11156063 3 17
+26 11156063 4 17
+26 11156063 5 17
+26 58182142 1 9
+26 58182142 2 9
+26 58182142 3 9
+26 58182142 4 9
+26 58182142 5 9
+26 25321691 1 10
+26 25321691 2 10
+26 25321691 3 10
+26 25321691 4 10
+26 25321691 5 10
+26 49670869 1 10
+26 49670869 2 10
+26 49670869 3 10
+26 49670869 4 10
+26 49670869 5 10
+26 9604075 1 6
+26 9604075 2 6
+26 9604075 3 6
+26 9604075 4 6
+26 9604075 5 6
+26 21246120 1 17
+26 21246120 2 17
+26 21246120 3 17
+26 21246120 4 17
+26 21246120 5 17
+26 54324966 1 15
+26 54324966 2 15
+26 54324966 3 15
+26 54324966 4 15
+26 54324966 5 15
+26 12222142 1 4
+26 12222142 2 4
+26 12222142 3 4
+26 12222142 4 4
+26 12222142 5 4
+26 46795936 1 10
+26 46795936 2 10
+26 46795936 3 10
+26 46795936 4 10
+26 46795936 5 10
+26 28991713 1 0
+26 28991713 2 0
+26 28991713 3 0
+26 28991713 4 0
+26 28991713 5 0
+26 21341767 1 6
+26 21341767 2 6
+26 21341767 3 6
+26 21341767 4 6
+26 21341767 5 6
+26 35735637 1 15
+26 35735637 2 15
+26 35735637 3 15
+26 35735637 4 15
+26 35735637 5 15
+26 20661103 1 13
+26 20661103 2 13
+26 20661103 3 13
+26 20661103 4 13
+26 20661103 5 13
+26 40707078 1 6
+26 40707078 2 6
+26 40707078 3 6
+26 40707078 4 6
+26 40707078 5 6
+26 53127018 1 12
+26 53127018 2 12
+26 53127018 3 12
+26 53127018 4 12
+26 53127018 5 12
+26 43370495 1 7
+26 43370495 2 7
+26 43370495 3 7
+26 43370495 4 7
+26 43370495 5 7
+26 4048861 1 10
+26 4048861 2 10
+26 4048861 3 10
+26 4048861 4 10
+26 4048861 5 10
+26 30464035 1 15
+26 30464035 2 15
+26 30464035 3 15
+26 30464035 4 15
+26 30464035 5 15
+26 5183631 1 9
+26 5183631 2 9
+26 5183631 3 9
+26 5183631 4 9
+26 5183631 5 9
+26 27077142 1 1
+26 27077142 2 1
+26 27077142 3 1
+26 27077142 4 1
+26 27077142 5 1
+26 48775300 1 6
+26 48775300 2 6
+26 48775300 3 6
+26 48775300 4 6
+26 48775300 5 6
+26 13488763 1 12
+26 13488763 2 12
+26 13488763 3 12
+26 13488763 4 12
+26 13488763 5 12
+26 13536330 1 8
+26 13536330 2 8
+26 13536330 3 8
+26 13536330 4 8
+26 13536330 5 8
+26 35410276 1 9
+26 35410276 2 9
+26 35410276 3 9
+26 35410276 4 9
+26 35410276 5 9
+26 53719442 1 12
+26 53719442 2 12
+26 53719442 3 12
+26 53719442 4 12
+26 53719442 5 12
+26 38572550 1 8
+26 38572550 2 8
+26 38572550 3 8
+26 38572550 4 8
+26 38572550 5 8
+26 66500609 1 4
+26 66500609 2 4
+26 66500609 3 4
+26 66500609 4 4
+26 66500609 5 4
+26 56930732 1 5
+26 56930732 2 5
+26 56930732 3 5
+26 56930732 4 5
+26 56930732 5 5
+26 13245256 1 7
+26 13245256 2 7
+26 13245256 3 7
+26 13245256 4 7
+26 13245256 5 7
+26 2474478 1 9
+26 2474478 2 9
+26 2474478 3 9
+26 2474478 4 9
+26 2474478 5 9
+26 47282801 1 12
+26 47282801 2 12
+26 47282801 3 12
+26 47282801 4 12
+26 47282801 5 12
+26 1178146 1 3
+26 1178146 2 3
+26 1178146 3 3
+26 1178146 4 3
+26 1178146 5 3
+26 43673724 1 6
+26 43673724 2 6
+26 43673724 3 6
+26 43673724 4 6
+26 43673724 5 6
+26 2100241 1 6
+26 2100241 2 6
+26 2100241 3 6
+26 2100241 4 6
+26 2100241 5 6
+26 41497130 1 0
+26 41497130 2 0
+26 41497130 3 0
+26 41497130 4 0
+26 41497130 5 0
+26 33722349 1 2
+26 33722349 2 2
+26 33722349 3 2
+26 33722349 4 2
+26 33722349 5 2
+26 9153815 1 12
+26 9153815 2 12
+26 9153815 3 12
+26 9153815 4 12
+26 9153815 5 12
+26 48610178 1 7
+26 48610178 2 7
+26 48610178 3 7
+26 48610178 4 7
+26 48610178 5 7
+26 53568526 1 14
+26 53568526 2 14
+26 53568526 3 14
+26 53568526 4 14
+26 53568526 5 14
+26 32823468 1 2
+26 32823468 2 2
+26 32823468 3 2
+26 32823468 4 2
+26 32823468 5 2
+26 65647768 1 14
+26 65647768 2 14
+26 65647768 3 14
+26 65647768 4 14
+26 65647768 5 14
+26 35401480 1 15
+26 35401480 2 15
+26 35401480 3 15
+26 35401480 4 15
+26 35401480 5 15
+26 41791958 1 12
+26 41791958 2 12
+26 41791958 3 12
+26 41791958 4 12
+26 41791958 5 12
+26 9655534 1 8
+26 9655534 2 8
+26 9655534 3 8
+26 9655534 4 8
+26 9655534 5 8
+26 40165520 1 1
+26 40165520 2 1
+26 40165520 3 1
+26 40165520 4 1
+26 40165520 5 1
+26 34020254 1 12
+26 34020254 2 12
+26 34020254 3 12
+26 34020254 4 12
+26 34020254 5 12
+26 61939853 1 8
+26 61939853 2 8
+26 61939853 3 8
+26 61939853 4 8
+26 61939853 5 8
+27 92315981 1 2
+27 92315981 2 2
+27 92315981 3 2
+27 92315981 4 2
+27 92315981 5 2
+27 61792721 1 8
+27 61792721 2 8
+27 61792721 3 8
+27 61792721 4 8
+27 61792721 5 8
+27 92388693 1 1
+27 92388693 2 1
+27 92388693 3 1
+27 92388693 4 1
+27 92388693 5 1
+27 53427871 1 17
+27 53427871 2 17
+27 53427871 3 17
+27 53427871 4 17
+27 53427871 5 17
+27 120842826 1 9
+27 120842826 2 9
+27 120842826 3 9
+27 120842826 4 9
+27 120842826 5 9
+27 28583319 1 10
+27 28583319 2 10
+27 28583319 3 10
+27 28583319 4 10
+27 28583319 5 10
+27 124744556 1 9
+27 124744556 2 9
+27 124744556 3 9
+27 124744556 4 9
+27 124744556 5 9
+27 4355438 1 0
+27 4355438 2 0
+27 4355438 3 0
+27 4355438 4 0
+27 4355438 5 0
+27 4216154 1 9
+27 4216154 2 9
+27 4216154 3 9
+27 4216154 4 9
+27 4216154 5 9
+27 123239172 1 13
+27 123239172 2 13
+27 123239172 3 13
+27 123239172 4 13
+27 123239172 5 13
+27 115756467 1 4
+27 115756467 2 4
+27 115756467 3 4
+27 115756467 4 4
+27 115756467 5 4
+27 51430308 1 9
+27 51430308 2 9
+27 51430308 3 9
+27 51430308 4 9
+27 51430308 5 9
+27 64209151 1 13
+27 64209151 2 13
+27 64209151 3 13
+27 64209151 4 13
+27 64209151 5 13
+27 86593418 1 6
+27 86593418 2 6
+27 86593418 3 6
+27 86593418 4 6
+27 86593418 5 6
+27 18520784 1 17
+27 18520784 2 17
+27 18520784 3 17
+27 18520784 4 17
+27 18520784 5 17
+27 99412133 1 3
+27 99412133 2 3
+27 99412133 3 3
+27 99412133 4 3
+27 99412133 5 3
+27 17075236 1 6
+27 17075236 2 6
+27 17075236 3 6
+27 17075236 4 6
+27 17075236 5 6
+27 9740701 1 10
+27 9740701 2 10
+27 9740701 3 10
+27 9740701 4 10
+27 9740701 5 10
+27 42355725 1 17
+27 42355725 2 17
+27 42355725 3 17
+27 42355725 4 17
+27 42355725 5 17
+27 76792086 1 12
+27 76792086 2 12
+27 76792086 3 12
+27 76792086 4 12
+27 76792086 5 12
+27 34848403 1 4
+27 34848403 2 4
+27 34848403 3 4
+27 34848403 4 4
+27 34848403 5 4
+27 60857654 1 4
+27 60857654 2 4
+27 60857654 3 4
+27 60857654 4 4
+27 60857654 5 4
+27 89466329 1 1
+27 89466329 2 1
+27 89466329 3 1
+27 89466329 4 1
+27 89466329 5 1
+27 7416677 1 0
+27 7416677 2 0
+27 7416677 3 0
+27 7416677 4 0
+27 7416677 5 0
+27 94093693 1 17
+27 94093693 2 17
+27 94093693 3 17
+27 94093693 4 17
+27 94093693 5 17
+27 71977043 1 0
+27 71977043 2 0
+27 71977043 3 0
+27 71977043 4 0
+27 71977043 5 0
+27 32931909 1 1
+27 32931909 2 1
+27 32931909 3 1
+27 32931909 4 1
+27 32931909 5 1
+27 99417150 1 1
+27 99417150 2 1
+27 99417150 3 1
+27 99417150 4 1
+27 99417150 5 1
+27 78489591 1 5
+27 78489591 2 5
+27 78489591 3 5
+27 78489591 4 5
+27 78489591 5 5
+27 56442740 1 17
+27 56442740 2 17
+27 56442740 3 17
+27 56442740 4 17
+27 56442740 5 17
+27 49715079 1 8
+27 49715079 2 8
+27 49715079 3 8
+27 49715079 4 8
+27 49715079 5 8
+27 95552279 1 5
+27 95552279 2 5
+27 95552279 3 5
+27 95552279 4 5
+27 95552279 5 5
+27 119474039 1 13
+27 119474039 2 13
+27 119474039 3 13
+27 119474039 4 13
+27 119474039 5 13
+27 47612448 1 12
+27 47612448 2 12
+27 47612448 3 12
+27 47612448 4 12
+27 47612448 5 12
+27 125922426 1 14
+27 125922426 2 14
+27 125922426 3 14
+27 125922426 4 14
+27 125922426 5 14
+27 18947749 1 8
+27 18947749 2 8
+27 18947749 3 8
+27 18947749 4 8
+27 18947749 5 8
+27 92954715 1 5
+27 92954715 2 5
+27 92954715 3 5
+27 92954715 4 5
+27 92954715 5 5
+27 69488478 1 7
+27 69488478 2 7
+27 69488478 3 7
+27 69488478 4 7
+27 69488478 5 7
+27 36779293 1 0
+27 36779293 2 0
+27 36779293 3 0
+27 36779293 4 0
+27 36779293 5 0
+27 90333541 1 4
+27 90333541 2 4
+27 90333541 3 4
+27 90333541 4 4
+27 90333541 5 4
+27 113514082 1 1
+27 113514082 2 1
+27 113514082 3 1
+27 113514082 4 1
+27 113514082 5 1
+27 114627133 1 2
+27 114627133 2 2
+27 114627133 3 2
+27 114627133 4 2
+27 114627133 5 2
+27 67788048 1 12
+27 67788048 2 12
+27 67788048 3 12
+27 67788048 4 12
+27 67788048 5 12
+27 80102932 1 6
+27 80102932 2 6
+27 80102932 3 6
+27 80102932 4 6
+27 80102932 5 6
+27 80083249 1 4
+27 80083249 2 4
+27 80083249 3 4
+27 80083249 4 4
+27 80083249 5 4
+27 8871500 1 0
+27 8871500 2 0
+27 8871500 3 0
+27 8871500 4 0
+27 8871500 5 0
+27 96933402 1 10
+27 96933402 2 10
+27 96933402 3 10
+27 96933402 4 10
+27 96933402 5 10
+27 40432695 1 17
+27 40432695 2 17
+27 40432695 3 17
+27 40432695 4 17
+27 40432695 5 17
+27 55794895 1 13
+27 55794895 2 13
+27 55794895 3 13
+27 55794895 4 13
+27 55794895 5 13
+27 120388642 1 6
+27 120388642 2 6
+27 120388642 3 6
+27 120388642 4 6
+27 120388642 5 6
+27 64256165 1 0
+27 64256165 2 0
+27 64256165 3 0
+27 64256165 4 0
+27 64256165 5 0
+27 4822164 1 0
+27 4822164 2 0
+27 4822164 3 0
+27 4822164 4 0
+27 4822164 5 0
+27 14139945 1 12
+27 14139945 2 12
+27 14139945 3 12
+27 14139945 4 12
+27 14139945 5 12
+27 116590039 1 0
+27 116590039 2 0
+27 116590039 3 0
+27 116590039 4 0
+27 116590039 5 0
+27 61027392 1 6
+27 61027392 2 6
+27 61027392 3 6
+27 61027392 4 6
+27 61027392 5 6
+27 71808439 1 4
+27 71808439 2 4
+27 71808439 3 4
+27 71808439 4 4
+27 71808439 5 4
+27 4329359 1 4
+27 4329359 2 4
+27 4329359 3 4
+27 4329359 4 4
+27 4329359 5 4
+27 90248073 1 2
+27 90248073 2 2
+27 90248073 3 2
+27 90248073 4 2
+27 90248073 5 2
+27 53334044 1 17
+27 53334044 2 17
+27 53334044 3 17
+27 53334044 4 17
+27 53334044 5 17
+27 79216751 1 12
+27 79216751 2 12
+27 79216751 3 12
+27 79216751 4 12
+27 79216751 5 12
+27 14571829 1 6
+27 14571829 2 6
+27 14571829 3 6
+27 14571829 4 6
+27 14571829 5 6
+27 58816473 1 5
+27 58816473 2 5
+27 58816473 3 5
+27 58816473 4 5
+27 58816473 5 5
+27 97942416 1 15
+27 97942416 2 15
+27 97942416 3 15
+27 97942416 4 15
+27 97942416 5 15
+27 25656398 1 9
+27 25656398 2 9
+27 25656398 3 9
+27 25656398 4 9
+27 25656398 5 9
+28 115821936 1 15
+28 115821936 2 15
+28 115821936 3 15
+28 115821936 4 15
+28 115821936 5 15
+28 108711265 1 3
+28 108711265 2 3
+28 108711265 3 3
+28 108711265 4 3
+28 108711265 5 3
+28 51814809 1 8
+28 51814809 2 8
+28 51814809 3 8
+28 51814809 4 8
+28 51814809 5 8
+28 9511812 1 3
+28 9511812 2 3
+28 9511812 3 3
+28 9511812 4 3
+28 9511812 5 3
+28 119984430 1 14
+28 119984430 2 14
+28 119984430 3 14
+28 119984430 4 14
+28 119984430 5 14
+28 222765195 1 1
+28 222765195 2 1
+28 222765195 3 1
+28 222765195 4 1
+28 222765195 5 1
+28 44273960 1 13
+28 44273960 2 13
+28 44273960 3 13
+28 44273960 4 13
+28 44273960 5 13
+28 146489653 1 8
+28 146489653 2 8
+28 146489653 3 8
+28 146489653 4 8
+28 146489653 5 8
+28 242813898 1 9
+28 242813898 2 9
+28 242813898 3 9
+28 242813898 4 9
+28 242813898 5 9
+28 145291726 1 6
+28 145291726 2 6
+28 145291726 3 6
+28 145291726 4 6
+28 145291726 5 6
+28 64513013 1 1
+28 64513013 2 1
+28 64513013 3 1
+28 64513013 4 1
+28 64513013 5 1
+28 214162337 1 13
+28 214162337 2 13
+28 214162337 3 13
+28 214162337 4 13
+28 214162337 5 13
+28 210803129 1 2
+28 210803129 2 2
+28 210803129 3 2
+28 210803129 4 2
+28 210803129 5 2
+28 60497323 1 5
+28 60497323 2 5
+28 60497323 3 5
+28 60497323 4 5
+28 60497323 5 5
+28 188261423 1 9
+28 188261423 2 9
+28 188261423 3 9
+28 188261423 4 9
+28 188261423 5 9
+28 140541072 1 14
+28 140541072 2 14
+28 140541072 3 14
+28 140541072 4 14
+28 140541072 5 14
+28 33608837 1 17
+28 33608837 2 17
+28 33608837 3 17
+28 33608837 4 17
+28 33608837 5 17
+28 69772754 1 10
+28 69772754 2 10
+28 69772754 3 10
+28 69772754 4 10
+28 69772754 5 10
+28 231659097 1 3
+28 231659097 2 3
+28 231659097 3 3
+28 231659097 4 3
+28 231659097 5 3
+28 65708608 1 4
+28 65708608 2 4
+28 65708608 3 4
+28 65708608 4 4
+28 65708608 5 4
+28 27844939 1 5
+28 27844939 2 5
+28 27844939 3 5
+28 27844939 4 5
+28 27844939 5 5
+28 250016684 1 1
+28 250016684 2 1
+28 250016684 3 1
+28 250016684 4 1
+28 250016684 5 1
+28 27914189 1 10
+28 27914189 2 10
+28 27914189 3 10
+28 27914189 4 10
+28 27914189 5 10
+28 242637280 1 2
+28 242637280 2 2
+28 242637280 3 2
+28 242637280 4 2
+28 242637280 5 2
+28 100798268 1 4
+28 100798268 2 4
+28 100798268 3 4
+28 100798268 4 4
+28 100798268 5 4
+28 63664849 1 2
+28 63664849 2 2
+28 63664849 3 2
+28 63664849 4 2
+28 63664849 5 2
+28 186850612 1 9
+28 186850612 2 9
+28 186850612 3 9
+28 186850612 4 9
+28 186850612 5 9
+28 154249749 1 3
+28 154249749 2 3
+28 154249749 3 3
+28 154249749 4 3
+28 154249749 5 3
+28 90932767 1 8
+28 90932767 2 8
+28 90932767 3 8
+28 90932767 4 8
+28 90932767 5 8
+28 101133202 1 7
+28 101133202 2 7
+28 101133202 3 7
+28 101133202 4 7
+28 101133202 5 7
+28 161863951 1 13
+28 161863951 2 13
+28 161863951 3 13
+28 161863951 4 13
+28 161863951 5 13
+28 106351991 1 13
+28 106351991 2 13
+28 106351991 3 13
+28 106351991 4 13
+28 106351991 5 13
+28 164447437 1 6
+28 164447437 2 6
+28 164447437 3 6
+28 164447437 4 6
+28 164447437 5 6
+28 198321520 1 8
+28 198321520 2 8
+28 198321520 3 8
+28 198321520 4 8
+28 198321520 5 8
+28 66343474 1 5
+28 66343474 2 5
+28 66343474 3 5
+28 66343474 4 5
+28 66343474 5 5
+28 221986069 1 14
+28 221986069 2 14
+28 221986069 3 14
+28 221986069 4 14
+28 221986069 5 14
+28 19689396 1 0
+28 19689396 2 0
+28 19689396 3 0
+28 19689396 4 0
+28 19689396 5 0
+28 105945506 1 12
+28 105945506 2 12
+28 105945506 3 12
+28 105945506 4 12
+28 105945506 5 12
+28 153231939 1 9
+28 153231939 2 9
+28 153231939 3 9
+28 153231939 4 9
+28 153231939 5 9
+28 205884141 1 10
+28 205884141 2 10
+28 205884141 3 10
+28 205884141 4 10
+28 205884141 5 10
+28 101379925 1 0
+28 101379925 2 0
+28 101379925 3 0
+28 101379925 4 0
+28 101379925 5 0
+28 217838996 1 0
+28 217838996 2 0
+28 217838996 3 0
+28 217838996 4 0
+28 217838996 5 0
+28 146756671 1 10
+28 146756671 2 10
+28 146756671 3 10
+28 146756671 4 10
+28 146756671 5 10
+28 13896821 1 2
+28 13896821 2 2
+28 13896821 3 2
+28 13896821 4 2
+28 13896821 5 2
+28 262954695 1 8
+28 262954695 2 8
+28 262954695 3 8
+28 262954695 4 8
+28 262954695 5 8
+28 188329314 1 14
+28 188329314 2 14
+28 188329314 3 14
+28 188329314 4 14
+28 188329314 5 14
+28 166574838 1 12
+28 166574838 2 12
+28 166574838 3 12
+28 166574838 4 12
+28 166574838 5 12
+28 73291029 1 10
+28 73291029 2 10
+28 73291029 3 10
+28 73291029 4 10
+28 73291029 5 10
+28 60443185 1 17
+28 60443185 2 17
+28 60443185 3 17
+28 60443185 4 17
+28 60443185 5 17
+28 168418913 1 14
+28 168418913 2 14
+28 168418913 3 14
+28 168418913 4 14
+28 168418913 5 14
+28 106600330 1 4
+28 106600330 2 4
+28 106600330 3 4
+28 106600330 4 4
+28 106600330 5 4
+28 224100522 1 13
+28 224100522 2 13
+28 224100522 3 13
+28 224100522 4 13
+28 224100522 5 13
+28 50445651 1 13
+28 50445651 2 13
+28 50445651 3 13
+28 50445651 4 13
+28 50445651 5 13
+28 49791383 1 0
+28 49791383 2 0
+28 49791383 3 0
+28 49791383 4 0
+28 49791383 5 0
+28 56004596 1 7
+28 56004596 2 7
+28 56004596 3 7
+28 56004596 4 7
+28 56004596 5 7
+28 163008005 1 9
+28 163008005 2 9
+28 163008005 3 9
+28 163008005 4 9
+28 163008005 5 9
+28 130294270 1 8
+28 130294270 2 8
+28 130294270 3 8
+28 130294270 4 8
+28 130294270 5 8
+28 79031870 1 7
+28 79031870 2 7
+28 79031870 3 7
+28 79031870 4 7
+28 79031870 5 7
+28 8779135 1 7
+28 8779135 2 7
+28 8779135 3 7
+28 8779135 4 7
+28 8779135 5 7
+28 132122986 1 3
+28 132122986 2 3
+28 132122986 3 3
+28 132122986 4 3
+28 132122986 5 3
+28 106262167 1 3
+28 106262167 2 3
+28 106262167 3 3
+28 106262167 4 3
+28 106262167 5 3
+28 84962373 1 14
+28 84962373 2 14
+28 84962373 3 14
+28 84962373 4 14
+28 84962373 5 14
+28 149117771 1 2
+28 149117771 2 2
+28 149117771 3 2
+28 149117771 4 2
+28 149117771 5 2
+28 179783442 1 15
+28 179783442 2 15
+28 179783442 3 15
+28 179783442 4 15
+28 179783442 5 15
+29 335271491 1 6
+29 335271491 2 6
+29 335271491 3 6
+29 335271491 4 6
+29 335271491 5 6
+29 10720791 1 17
+29 10720791 2 17
+29 10720791 3 17
+29 10720791 4 17
+29 10720791 5 17
+29 500040308 1 0
+29 500040308 2 0
+29 500040308 3 0
+29 500040308 4 0
+29 500040308 5 0
+29 510755966 1 8
+29 510755966 2 8
+29 510755966 3 8
+29 510755966 4 8
+29 510755966 5 8
+29 227186933 1 15
+29 227186933 2 15
+29 227186933 3 15
+29 227186933 4 15
+29 227186933 5 15
+29 422662843 1 13
+29 422662843 2 13
+29 422662843 3 13
+29 422662843 4 13
+29 422662843 5 13
+29 81866932 1 3
+29 81866932 2 3
+29 81866932 3 3
+29 81866932 4 3
+29 81866932 5 3
+29 470195498 1 9
+29 470195498 2 9
+29 470195498 3 9
+29 470195498 4 9
+29 470195498 5 9
+29 505281812 1 6
+29 505281812 2 6
+29 505281812 3 6
+29 505281812 4 6
+29 505281812 5 6
+29 42328055 1 17
+29 42328055 2 17
+29 42328055 3 17
+29 42328055 4 17
+29 42328055 5 17
+29 510604597 1 4
+29 510604597 2 4
+29 510604597 3 4
+29 510604597 4 4
+29 510604597 5 4
+29 380926471 1 10
+29 380926471 2 10
+29 380926471 3 10
+29 380926471 4 10
+29 380926471 5 10
+29 159591288 1 5
+29 159591288 2 5
+29 159591288 3 5
+29 159591288 4 5
+29 159591288 5 5
+29 189495832 1 13
+29 189495832 2 13
+29 189495832 3 13
+29 189495832 4 13
+29 189495832 5 13
+29 7461185 1 1
+29 7461185 2 1
+29 7461185 3 1
+29 7461185 4 1
+29 7461185 5 1
+29 41392678 1 15
+29 41392678 2 15
+29 41392678 3 15
+29 41392678 4 15
+29 41392678 5 15
+29 466412287 1 7
+29 466412287 2 7
+29 466412287 3 7
+29 466412287 4 7
+29 466412287 5 7
+29 269683984 1 10
+29 269683984 2 10
+29 269683984 3 10
+29 269683984 4 10
+29 269683984 5 10
+29 81614953 1 14
+29 81614953 2 14
+29 81614953 3 14
+29 81614953 4 14
+29 81614953 5 14
+29 117179003 1 4
+29 117179003 2 4
+29 117179003 3 4
+29 117179003 4 4
+29 117179003 5 4
+29 348566793 1 17
+29 348566793 2 17
+29 348566793 3 17
+29 348566793 4 17
+29 348566793 5 17
+29 502596854 1 4
+29 502596854 2 4
+29 502596854 3 4
+29 502596854 4 4
+29 502596854 5 4
+29 364569853 1 17
+29 364569853 2 17
+29 364569853 3 17
+29 364569853 4 17
+29 364569853 5 17
+29 262837855 1 5
+29 262837855 2 5
+29 262837855 3 5
+29 262837855 4 5
+29 262837855 5 5
+29 316887548 1 10
+29 316887548 2 10
+29 316887548 3 10
+29 316887548 4 10
+29 316887548 5 10
+29 223063684 1 4
+29 223063684 2 4
+29 223063684 3 4
+29 223063684 4 4
+29 223063684 5 4
+29 459226263 1 15
+29 459226263 2 15
+29 459226263 3 15
+29 459226263 4 15
+29 459226263 5 15
+29 299433996 1 5
+29 299433996 2 5
+29 299433996 3 5
+29 299433996 4 5
+29 299433996 5 5
+29 200795585 1 15
+29 200795585 2 15
+29 200795585 3 15
+29 200795585 4 15
+29 200795585 5 15
+29 136914840 1 13
+29 136914840 2 13
+29 136914840 3 13
+29 136914840 4 13
+29 136914840 5 13
+29 237980817 1 17
+29 237980817 2 17
+29 237980817 3 17
+29 237980817 4 17
+29 237980817 5 17
+29 350103844 1 14
+29 350103844 2 14
+29 350103844 3 14
+29 350103844 4 14
+29 350103844 5 14
+29 441877573 1 3
+29 441877573 2 3
+29 441877573 3 3
+29 441877573 4 3
+29 441877573 5 3
+29 40558515 1 10
+29 40558515 2 10
+29 40558515 3 10
+29 40558515 4 10
+29 40558515 5 10
+29 161801865 1 7
+29 161801865 2 7
+29 161801865 3 7
+29 161801865 4 7
+29 161801865 5 7
+29 504185643 1 5
+29 504185643 2 5
+29 504185643 3 5
+29 504185643 4 5
+29 504185643 5 5
+29 85566969 1 13
+29 85566969 2 13
+29 85566969 3 13
+29 85566969 4 13
+29 85566969 5 13
+29 59549821 1 0
+29 59549821 2 0
+29 59549821 3 0
+29 59549821 4 0
+29 59549821 5 0
+29 42304740 1 6
+29 42304740 2 6
+29 42304740 3 6
+29 42304740 4 6
+29 42304740 5 6
+29 14245896 1 6
+29 14245896 2 6
+29 14245896 3 6
+29 14245896 4 6
+29 14245896 5 6
+29 313701459 1 12
+29 313701459 2 12
+29 313701459 3 12
+29 313701459 4 12
+29 313701459 5 12
+29 77420095 1 6
+29 77420095 2 6
+29 77420095 3 6
+29 77420095 4 6
+29 77420095 5 6
+29 243081033 1 1
+29 243081033 2 1
+29 243081033 3 1
+29 243081033 4 1
+29 243081033 5 1
+29 430152328 1 10
+29 430152328 2 10
+29 430152328 3 10
+29 430152328 4 10
+29 430152328 5 10
+29 84780619 1 17
+29 84780619 2 17
+29 84780619 3 17
+29 84780619 4 17
+29 84780619 5 17
+29 251064423 1 5
+29 251064423 2 5
+29 251064423 3 5
+29 251064423 4 5
+29 251064423 5 5
+29 529469218 1 13
+29 529469218 2 13
+29 529469218 3 13
+29 529469218 4 13
+29 529469218 5 13
+29 133549787 1 12
+29 133549787 2 12
+29 133549787 3 12
+29 133549787 4 12
+29 133549787 5 12
+29 383495391 1 2
+29 383495391 2 2
+29 383495391 3 2
+29 383495391 4 2
+29 383495391 5 2
+29 446460424 1 1
+29 446460424 2 1
+29 446460424 3 1
+29 446460424 4 1
+29 446460424 5 1
+29 302973982 1 15
+29 302973982 2 15
+29 302973982 3 15
+29 302973982 4 15
+29 302973982 5 15
+29 321643285 1 2
+29 321643285 2 2
+29 321643285 3 2
+29 321643285 4 2
+29 321643285 5 2
+29 299298703 1 17
+29 299298703 2 17
+29 299298703 3 17
+29 299298703 4 17
+29 299298703 5 17
+29 90118743 1 13
+29 90118743 2 13
+29 90118743 3 13
+29 90118743 4 13
+29 90118743 5 13
+29 269748402 1 5
+29 269748402 2 5
+29 269748402 3 5
+29 269748402 4 5
+29 269748402 5 5
+29 47030190 1 6
+29 47030190 2 6
+29 47030190 3 6
+29 47030190 4 6
+29 47030190 5 6
+29 504453345 1 14
+29 504453345 2 14
+29 504453345 3 14
+29 504453345 4 14
+29 504453345 5 14
+29 506285359 1 10
+29 506285359 2 10
+29 506285359 3 10
+29 506285359 4 10
+29 506285359 5 10
+29 429364883 1 0
+29 429364883 2 0
+29 429364883 3 0
+29 429364883 4 0
+29 429364883 5 0
+29 437983235 1 3
+29 437983235 2 3
+29 437983235 3 3
+29 437983235 4 3
+29 437983235 5 3
+29 446722782 1 1
+29 446722782 2 1
+29 446722782 3 1
+29 446722782 4 1
+29 446722782 5 1
+29 170722190 1 5
+29 170722190 2 5
+29 170722190 3 5
+29 170722190 4 5
+29 170722190 5 5
+29 347257661 1 1
+29 347257661 2 1
+29 347257661 3 1
+29 347257661 4 1
+29 347257661 5 1
+29 344826579 1 3
+29 344826579 2 3
+29 344826579 3 3
+29 344826579 4 3
+29 344826579 5 3
+30 213793736 1 17
+30 213793736 2 17
+30 213793736 3 17
+30 213793736 4 17
+30 213793736 5 17
+30 841563124 1 8
+30 841563124 2 8
+30 841563124 3 8
+30 841563124 4 8
+30 841563124 5 8
+30 497541093 1 0
+30 497541093 2 0
+30 497541093 3 0
+30 497541093 4 0
+30 497541093 5 0
+30 886071695 1 4
+30 886071695 2 4
+30 886071695 3 4
+30 886071695 4 4
+30 886071695 5 4
+30 442450336 1 15
+30 442450336 2 15
+30 442450336 3 15
+30 442450336 4 15
+30 442450336 5 15
+30 359840809 1 1
+30 359840809 2 1
+30 359840809 3 1
+30 359840809 4 1
+30 359840809 5 1
+30 237523472 1 7
+30 237523472 2 7
+30 237523472 3 7
+30 237523472 4 7
+30 237523472 5 7
+30 841255244 1 5
+30 841255244 2 5
+30 841255244 3 5
+30 841255244 4 5
+30 841255244 5 5
+30 254748983 1 7
+30 254748983 2 7
+30 254748983 3 7
+30 254748983 4 7
+30 254748983 5 7
+30 888089982 1 9
+30 888089982 2 9
+30 888089982 3 9
+30 888089982 4 9
+30 888089982 5 9
+30 514507124 1 17
+30 514507124 2 17
+30 514507124 3 17
+30 514507124 4 17
+30 514507124 5 17
+30 954375894 1 0
+30 954375894 2 0
+30 954375894 3 0
+30 954375894 4 0
+30 954375894 5 0
+30 313226812 1 1
+30 313226812 2 1
+30 313226812 3 1
+30 313226812 4 1
+30 313226812 5 1
+30 339371217 1 15
+30 339371217 2 15
+30 339371217 3 15
+30 339371217 4 15
+30 339371217 5 15
+30 818297353 1 4
+30 818297353 2 4
+30 818297353 3 4
+30 818297353 4 4
+30 818297353 5 4
+30 70402405 1 5
+30 70402405 2 5
+30 70402405 3 5
+30 70402405 4 5
+30 70402405 5 5
+30 778614673 1 10
+30 778614673 2 10
+30 778614673 3 10
+30 778614673 4 10
+30 778614673 5 10
+30 475256662 1 14
+30 475256662 2 14
+30 475256662 3 14
+30 475256662 4 14
+30 475256662 5 14
+30 263311931 1 2
+30 263311931 2 2
+30 263311931 3 2
+30 263311931 4 2
+30 263311931 5 2
+30 499638729 1 3
+30 499638729 2 3
+30 499638729 3 3
+30 499638729 4 3
+30 499638729 5 3
+30 191707598 1 9
+30 191707598 2 9
+30 191707598 3 9
+30 191707598 4 9
+30 191707598 5 9
+30 13291798 1 17
+30 13291798 2 17
+30 13291798 3 17
+30 13291798 4 17
+30 13291798 5 17
+30 428344683 1 2
+30 428344683 2 2
+30 428344683 3 2
+30 428344683 4 2
+30 428344683 5 2
+30 470671586 1 14
+30 470671586 2 14
+30 470671586 3 14
+30 470671586 4 14
+30 470671586 5 14
+30 1010796989 1 7
+30 1010796989 2 7
+30 1010796989 3 7
+30 1010796989 4 7
+30 1010796989 5 7
+30 550173547 1 5
+30 550173547 2 5
+30 550173547 3 5
+30 550173547 4 5
+30 550173547 5 5
+30 984276590 1 3
+30 984276590 2 3
+30 984276590 3 3
+30 984276590 4 3
+30 984276590 5 3
+30 400752165 1 15
+30 400752165 2 15
+30 400752165 3 15
+30 400752165 4 15
+30 400752165 5 15
+30 676513500 1 0
+30 676513500 2 0
+30 676513500 3 0
+30 676513500 4 0
+30 676513500 5 0
+30 29569926 1 13
+30 29569926 2 13
+30 29569926 3 13
+30 29569926 4 13
+30 29569926 5 13
+30 814936588 1 2
+30 814936588 2 2
+30 814936588 3 2
+30 814936588 4 2
+30 814936588 5 2
+30 424154654 1 1
+30 424154654 2 1
+30 424154654 3 1
+30 424154654 4 1
+30 424154654 5 1
+30 414893534 1 1
+30 414893534 2 1
+30 414893534 3 1
+30 414893534 4 1
+30 414893534 5 1
+30 1050718441 1 6
+30 1050718441 2 6
+30 1050718441 3 6
+30 1050718441 4 6
+30 1050718441 5 6
+30 680733058 1 8
+30 680733058 2 8
+30 680733058 3 8
+30 680733058 4 8
+30 680733058 5 8
+30 194457832 1 13
+30 194457832 2 13
+30 194457832 3 13
+30 194457832 4 13
+30 194457832 5 13
+30 961676074 1 3
+30 961676074 2 3
+30 961676074 3 3
+30 961676074 4 3
+30 961676074 5 3
+30 735607789 1 15
+30 735607789 2 15
+30 735607789 3 15
+30 735607789 4 15
+30 735607789 5 15
+30 375086337 1 6
+30 375086337 2 6
+30 375086337 3 6
+30 375086337 4 6
+30 375086337 5 6
+30 52289719 1 0
+30 52289719 2 0
+30 52289719 3 0
+30 52289719 4 0
+30 52289719 5 0
+30 482043226 1 1
+30 482043226 2 1
+30 482043226 3 1
+30 482043226 4 1
+30 482043226 5 1
+30 1035547710 1 4
+30 1035547710 2 4
+30 1035547710 3 4
+30 1035547710 4 4
+30 1035547710 5 4
+30 222543404 1 10
+30 222543404 2 10
+30 222543404 3 10
+30 222543404 4 10
+30 222543404 5 10
+30 1060433998 1 2
+30 1060433998 2 2
+30 1060433998 3 2
+30 1060433998 4 2
+30 1060433998 5 2
+30 887738302 1 7
+30 887738302 2 7
+30 887738302 3 7
+30 887738302 4 7
+30 887738302 5 7
+30 868165466 1 0
+30 868165466 2 0
+30 868165466 3 0
+30 868165466 4 0
+30 868165466 5 0
+30 1051398814 1 8
+30 1051398814 2 8
+30 1051398814 3 8
+30 1051398814 4 8
+30 1051398814 5 8
+30 489644425 1 6
+30 489644425 2 6
+30 489644425 3 6
+30 489644425 4 6
+30 489644425 5 6
+30 1024951511 1 15
+30 1024951511 2 15
+30 1024951511 3 15
+30 1024951511 4 15
+30 1024951511 5 15
+30 686077717 1 15
+30 686077717 2 15
+30 686077717 3 15
+30 686077717 4 15
+30 686077717 5 15
+30 1056030306 1 0
+30 1056030306 2 0
+30 1056030306 3 0
+30 1056030306 4 0
+30 1056030306 5 0
+30 565885909 1 8
+30 565885909 2 8
+30 565885909 3 8
+30 565885909 4 8
+30 565885909 5 8
+30 89610460 1 9
+30 89610460 2 9
+30 89610460 3 9
+30 89610460 4 9
+30 89610460 5 9
+30 774443031 1 2
+30 774443031 2 2
+30 774443031 3 2
+30 774443031 4 2
+30 774443031 5 2
+30 433823353 1 15
+30 433823353 2 15
+30 433823353 3 15
+30 433823353 4 15
+30 433823353 5 15
+30 394963635 1 3
+30 394963635 2 3
+30 394963635 3 3
+30 394963635 4 3
+30 394963635 5 3
+30 724153400 1 14
+30 724153400 2 14
+30 724153400 3 14
+30 724153400 4 14
+30 724153400 5 14
+30 29831260 1 4
+30 29831260 2 4
+30 29831260 3 4
+30 29831260 4 4
+30 29831260 5 4
+30 241349464 1 9
+30 241349464 2 9
+30 241349464 3 9
+30 241349464 4 9
+30 241349464 5 9
+30 57273401 1 3
+30 57273401 2 3
+30 57273401 3 3
+30 57273401 4 3
+30 57273401 5 3
+30 230647305 1 2
+30 230647305 2 2
+30 230647305 3 2
+30 230647305 4 2
+30 230647305 5 2
+30 181878195 1 15
+30 181878195 2 15
+30 181878195 3 15
+30 181878195 4 15
+30 181878195 5 15
+30 21273447 1 12
+30 21273447 2 12
+30 21273447 3 12
+30 21273447 4 12
+30 21273447 5 12
+30 386568080 1 6
+30 386568080 2 6
+30 386568080 3 6
+30 386568080 4 6
+30 386568080 5 6
+31 433243292 1 4
+31 433243292 2 4
+31 433243292 3 4
+31 433243292 4 4
+31 433243292 5 4
+31 743572650 1 9
+31 743572650 2 9
+31 743572650 3 9
+31 743572650 4 9
+31 743572650 5 9
+31 1751072959 1 3
+31 1751072959 2 3
+31 1751072959 3 3
+31 1751072959 4 3
+31 1751072959 5 3
+31 582009481 1 13
+31 582009481 2 13
+31 582009481 3 13
+31 582009481 4 13
+31 582009481 5 13
+31 1086523751 1 5
+31 1086523751 2 5
+31 1086523751 3 5
+31 1086523751 4 5
+31 1086523751 5 5
+31 1633480282 1 13
+31 1633480282 2 13
+31 1633480282 3 13
+31 1633480282 4 13
+31 1633480282 5 13
+31 543551900 1 8
+31 543551900 2 8
+31 543551900 3 8
+31 543551900 4 8
+31 543551900 5 8
+31 359654721 1 14
+31 359654721 2 14
+31 359654721 3 14
+31 359654721 4 14
+31 359654721 5 14
+31 517216897 1 8
+31 517216897 2 8
+31 517216897 3 8
+31 517216897 4 8
+31 517216897 5 8
+31 1321997222 1 7
+31 1321997222 2 7
+31 1321997222 3 7
+31 1321997222 4 7
+31 1321997222 5 7
+31 1765905076 1 10
+31 1765905076 2 10
+31 1765905076 3 10
+31 1765905076 4 10
+31 1765905076 5 10
+31 1658010939 1 2
+31 1658010939 2 2
+31 1658010939 3 2
+31 1658010939 4 2
+31 1658010939 5 2
+31 798885882 1 4
+31 798885882 2 4
+31 798885882 3 4
+31 798885882 4 4
+31 798885882 5 4
+31 1542111550 1 6
+31 1542111550 2 6
+31 1542111550 3 6
+31 1542111550 4 6
+31 1542111550 5 6
+31 1979674396 1 15
+31 1979674396 2 15
+31 1979674396 3 15
+31 1979674396 4 15
+31 1979674396 5 15
+31 1313431291 1 14
+31 1313431291 2 14
+31 1313431291 3 14
+31 1313431291 4 14
+31 1313431291 5 14
+31 1748289035 1 10
+31 1748289035 2 10
+31 1748289035 3 10
+31 1748289035 4 10
+31 1748289035 5 10
+31 2017345172 1 12
+31 2017345172 2 12
+31 2017345172 3 12
+31 2017345172 4 12
+31 2017345172 5 12
+31 1992315978 1 9
+31 1992315978 2 9
+31 1992315978 3 9
+31 1992315978 4 9
+31 1992315978 5 9
+31 1624850948 1 17
+31 1624850948 2 17
+31 1624850948 3 17
+31 1624850948 4 17
+31 1624850948 5 17
+31 780864908 1 15
+31 780864908 2 15
+31 780864908 3 15
+31 780864908 4 15
+31 780864908 5 15
+31 534307425 1 17
+31 534307425 2 17
+31 534307425 3 17
+31 534307425 4 17
+31 534307425 5 17
+31 1301871260 1 7
+31 1301871260 2 7
+31 1301871260 3 7
+31 1301871260 4 7
+31 1301871260 5 7
+31 222436705 1 6
+31 222436705 2 6
+31 222436705 3 6
+31 222436705 4 6
+31 222436705 5 6
+31 421579900 1 4
+31 421579900 2 4
+31 421579900 3 4
+31 421579900 4 4
+31 421579900 5 4
+31 2051749662 1 15
+31 2051749662 2 15
+31 2051749662 3 15
+31 2051749662 4 15
+31 2051749662 5 15
+31 1525087697 1 1
+31 1525087697 2 1
+31 1525087697 3 1
+31 1525087697 4 1
+31 1525087697 5 1
+31 9065501 1 7
+31 9065501 2 7
+31 9065501 3 7
+31 9065501 4 7
+31 9065501 5 7
+31 1054811774 1 14
+31 1054811774 2 14
+31 1054811774 3 14
+31 1054811774 4 14
+31 1054811774 5 14
+31 1675964300 1 5
+31 1675964300 2 5
+31 1675964300 3 5
+31 1675964300 4 5
+31 1675964300 5 5
+31 85747085 1 3
+31 85747085 2 3
+31 85747085 3 3
+31 85747085 4 3
+31 85747085 5 3
+31 2010083787 1 12
+31 2010083787 2 12
+31 2010083787 3 12
+31 2010083787 4 12
+31 2010083787 5 12
+31 960759126 1 1
+31 960759126 2 1
+31 960759126 3 1
+31 960759126 4 1
+31 960759126 5 1
+31 892955437 1 7
+31 892955437 2 7
+31 892955437 3 7
+31 892955437 4 7
+31 892955437 5 7
+31 1581497818 1 13
+31 1581497818 2 13
+31 1581497818 3 13
+31 1581497818 4 13
+31 1581497818 5 13
+31 2087270142 1 7
+31 2087270142 2 7
+31 2087270142 3 7
+31 2087270142 4 7
+31 2087270142 5 7
+31 1564424559 1 4
+31 1564424559 2 4
+31 1564424559 3 4
+31 1564424559 4 4
+31 1564424559 5 4
+31 1762953928 1 7
+31 1762953928 2 7
+31 1762953928 3 7
+31 1762953928 4 7
+31 1762953928 5 7
+31 264159138 1 14
+31 264159138 2 14
+31 264159138 3 14
+31 264159138 4 14
+31 264159138 5 14
+31 934393298 1 13
+31 934393298 2 13
+31 934393298 3 13
+31 934393298 4 13
+31 934393298 5 13
+31 425929304 1 8
+31 425929304 2 8
+31 425929304 3 8
+31 425929304 4 8
+31 425929304 5 8
+31 1431999721 1 9
+31 1431999721 2 9
+31 1431999721 3 9
+31 1431999721 4 9
+31 1431999721 5 9
+31 50432310 1 0
+31 50432310 2 0
+31 50432310 3 0
+31 50432310 4 0
+31 50432310 5 0
+31 671383138 1 0
+31 671383138 2 0
+31 671383138 3 0
+31 671383138 4 0
+31 671383138 5 0
+31 1514870594 1 15
+31 1514870594 2 15
+31 1514870594 3 15
+31 1514870594 4 15
+31 1514870594 5 15
+31 125594206 1 12
+31 125594206 2 12
+31 125594206 3 12
+31 125594206 4 12
+31 125594206 5 12
+31 340551370 1 4
+31 340551370 2 4
+31 340551370 3 4
+31 340551370 4 4
+31 340551370 5 4
+31 1623645007 1 15
+31 1623645007 2 15
+31 1623645007 3 15
+31 1623645007 4 15
+31 1623645007 5 15
+31 1348003716 1 4
+31 1348003716 2 4
+31 1348003716 3 4
+31 1348003716 4 4
+31 1348003716 5 4
+31 2037861051 1 7
+31 2037861051 2 7
+31 2037861051 3 7
+31 2037861051 4 7
+31 2037861051 5 7
+31 2057710326 1 5
+31 2057710326 2 5
+31 2057710326 3 5
+31 2057710326 4 5
+31 2057710326 5 5
+31 663428672 1 13
+31 663428672 2 13
+31 663428672 3 13
+31 663428672 4 13
+31 663428672 5 13
+31 1949076248 1 8
+31 1949076248 2 8
+31 1949076248 3 8
+31 1949076248 4 8
+31 1949076248 5 8
+31 1083205847 1 8
+31 1083205847 2 8
+31 1083205847 3 8
+31 1083205847 4 8
+31 1083205847 5 8
+31 1989744438 1 0
+31 1989744438 2 0
+31 1989744438 3 0
+31 1989744438 4 0
+31 1989744438 5 0
+31 815856732 1 9
+31 815856732 2 9
+31 815856732 3 9
+31 815856732 4 9
+31 815856732 5 9
+31 829877019 1 6
+31 829877019 2 6
+31 829877019 3 6
+31 829877019 4 6
+31 829877019 5 6
+31 188649293 1 10
+31 188649293 2 10
+31 188649293 3 10
+31 188649293 4 10
+31 188649293 5 10
+31 1198806123 1 1
+31 1198806123 2 1
+31 1198806123 3 1
+31 1198806123 4 1
+31 1198806123 5 1
+31 1973746385 1 4
+31 1973746385 2 4
+31 1973746385 3 4
+31 1973746385 4 4
+31 1973746385 5 4
+31 839543376 1 6
+31 839543376 2 6
+31 839543376 3 6
+31 839543376 4 6
+31 839543376 5 6
+31 1072944380 1 14
+31 1072944380 2 14
+31 1072944380 3 14
+31 1072944380 4 14
+31 1072944380 5 14
+31 1561590617 1 17
+31 1561590617 2 17
+31 1561590617 3 17
+31 1561590617 4 17
+31 1561590617 5 17
+31 551611217 1 10
+31 551611217 2 10
+31 551611217 3 10
+31 551611217 4 10
+31 551611217 5 10
+32 1036684082 1 9
+32 1036684082 2 9
+32 1036684082 3 9
+32 1036684082 4 9
+32 1036684082 5 9
+32 2486634245 1 10
+32 2486634245 2 10
+32 2486634245 3 10
+32 2486634245 4 10
+32 2486634245 5 10
+32 1960853583 1 14
+32 1960853583 2 14
+32 1960853583 3 14
+32 1960853583 4 14
+32 1960853583 5 14
+32 2216609468 1 3
+32 2216609468 2 3
+32 2216609468 3 3
+32 2216609468 4 3
+32 2216609468 5 3
+32 221178161 1 7
+32 221178161 2 7
+32 221178161 3 7
+32 221178161 4 7
+32 221178161 5 7
+32 439758692 1 3
+32 439758692 2 3
+32 439758692 3 3
+32 439758692 4 3
+32 439758692 5 3
+32 1129185496 1 12
+32 1129185496 2 12
+32 1129185496 3 12
+32 1129185496 4 12
+32 1129185496 5 12
+32 1867788184 1 4
+32 1867788184 2 4
+32 1867788184 3 4
+32 1867788184 4 4
+32 1867788184 5 4
+32 564853289 1 8
+32 564853289 2 8
+32 564853289 3 8
+32 564853289 4 8
+32 564853289 5 8
+32 2344179581 1 5
+32 2344179581 2 5
+32 2344179581 3 5
+32 2344179581 4 5
+32 2344179581 5 5
+32 2970472705 1 0
+32 2970472705 2 0
+32 2970472705 3 0
+32 2970472705 4 0
+32 2970472705 5 0
+32 4070187504 1 9
+32 4070187504 2 9
+32 4070187504 3 9
+32 4070187504 4 9
+32 4070187504 5 9
+32 2662144140 1 9
+32 2662144140 2 9
+32 2662144140 3 9
+32 2662144140 4 9
+32 2662144140 5 9
+32 4167572734 1 10
+32 4167572734 2 10
+32 4167572734 3 10
+32 4167572734 4 10
+32 4167572734 5 10
+32 927210200 1 6
+32 927210200 2 6
+32 927210200 3 6
+32 927210200 4 6
+32 927210200 5 6
+32 2208343448 1 5
+32 2208343448 2 5
+32 2208343448 3 5
+32 2208343448 4 5
+32 2208343448 5 5
+32 2192760228 1 3
+32 2192760228 2 3
+32 2192760228 3 3
+32 2192760228 4 3
+32 2192760228 5 3
+32 2166303367 1 7
+32 2166303367 2 7
+32 2166303367 3 7
+32 2166303367 4 7
+32 2166303367 5 7
+32 3688439934 1 6
+32 3688439934 2 6
+32 3688439934 3 6
+32 3688439934 4 6
+32 3688439934 5 6
+32 308030109 1 5
+32 308030109 2 5
+32 308030109 3 5
+32 308030109 4 5
+32 308030109 5 5
+32 1104848908 1 1
+32 1104848908 2 1
+32 1104848908 3 1
+32 1104848908 4 1
+32 1104848908 5 1
+32 3705758252 1 12
+32 3705758252 2 12
+32 3705758252 3 12
+32 3705758252 4 12
+32 3705758252 5 12
+32 336358057 1 2
+32 336358057 2 2
+32 336358057 3 2
+32 336358057 4 2
+32 336358057 5 2
+32 701422524 1 7
+32 701422524 2 7
+32 701422524 3 7
+32 701422524 4 7
+32 701422524 5 7
+32 95384115 1 9
+32 95384115 2 9
+32 95384115 3 9
+32 95384115 4 9
+32 95384115 5 9
+32 3922974711 1 14
+32 3922974711 2 14
+32 3922974711 3 14
+32 3922974711 4 14
+32 3922974711 5 14
+32 60262178 1 7
+32 60262178 2 7
+32 60262178 3 7
+32 60262178 4 7
+32 60262178 5 7
+32 2696528104 1 5
+32 2696528104 2 5
+32 2696528104 3 5
+32 2696528104 4 5
+32 2696528104 5 5
+32 19462365 1 15
+32 19462365 2 15
+32 19462365 3 15
+32 19462365 4 15
+32 19462365 5 15
+32 2463013988 1 12
+32 2463013988 2 12
+32 2463013988 3 12
+32 2463013988 4 12
+32 2463013988 5 12
+32 1023022920 1 3
+32 1023022920 2 3
+32 1023022920 3 3
+32 1023022920 4 3
+32 1023022920 5 3
+32 3781145032 1 13
+32 3781145032 2 13
+32 3781145032 3 13
+32 3781145032 4 13
+32 3781145032 5 13
+32 1830433185 1 10
+32 1830433185 2 10
+32 1830433185 3 10
+32 1830433185 4 10
+32 1830433185 5 10
+32 424433380 1 8
+32 424433380 2 8
+32 424433380 3 8
+32 424433380 4 8
+32 424433380 5 8
+32 1623797388 1 10
+32 1623797388 2 10
+32 1623797388 3 10
+32 1623797388 4 10
+32 1623797388 5 10
+32 3401848886 1 14
+32 3401848886 2 14
+32 3401848886 3 14
+32 3401848886 4 14
+32 3401848886 5 14
+32 1317540203 1 5
+32 1317540203 2 5
+32 1317540203 3 5
+32 1317540203 4 5
+32 1317540203 5 5
+32 1120055386 1 1
+32 1120055386 2 1
+32 1120055386 3 1
+32 1120055386 4 1
+32 1120055386 5 1
+32 454820083 1 0
+32 454820083 2 0
+32 454820083 3 0
+32 454820083 4 0
+32 454820083 5 0
+32 1359971009 1 14
+32 1359971009 2 14
+32 1359971009 3 14
+32 1359971009 4 14
+32 1359971009 5 14
+32 497197820 1 15
+32 497197820 2 15
+32 497197820 3 15
+32 497197820 4 15
+32 497197820 5 15
+32 4289564065 1 15
+32 4289564065 2 15
+32 4289564065 3 15
+32 4289564065 4 15
+32 4289564065 5 15
+32 124772759 1 17
+32 124772759 2 17
+32 124772759 3 17
+32 124772759 4 17
+32 124772759 5 17
+32 1308886828 1 1
+32 1308886828 2 1
+32 1308886828 3 1
+32 1308886828 4 1
+32 1308886828 5 1
+32 3243928933 1 10
+32 3243928933 2 10
+32 3243928933 3 10
+32 3243928933 4 10
+32 3243928933 5 10
+32 3788970499 1 1
+32 3788970499 2 1
+32 3788970499 3 1
+32 3788970499 4 1
+32 3788970499 5 1
+32 4103967014 1 0
+32 4103967014 2 0
+32 4103967014 3 0
+32 4103967014 4 0
+32 4103967014 5 0
+32 1705735405 1 10
+32 1705735405 2 10
+32 1705735405 3 10
+32 1705735405 4 10
+32 1705735405 5 10
+32 416033424 1 2
+32 416033424 2 2
+32 416033424 3 2
+32 416033424 4 2
+32 416033424 5 2
+32 514236867 1 4
+32 514236867 2 4
+32 514236867 3 4
+32 514236867 4 4
+32 514236867 5 4
+32 3686390881 1 4
+32 3686390881 2 4
+32 3686390881 3 4
+32 3686390881 4 4
+32 3686390881 5 4
+32 2125027247 1 12
+32 2125027247 2 12
+32 2125027247 3 12
+32 2125027247 4 12
+32 2125027247 5 12
+32 2029833655 1 8
+32 2029833655 2 8
+32 2029833655 3 8
+32 2029833655 4 8
+32 2029833655 5 8
+32 3917495445 1 7
+32 3917495445 2 7
+32 3917495445 3 7
+32 3917495445 4 7
+32 3917495445 5 7
+32 2650507935 1 5
+32 2650507935 2 5
+32 2650507935 3 5
+32 2650507935 4 5
+32 2650507935 5 5
+32 282773968 1 13
+32 282773968 2 13
+32 282773968 3 13
+32 282773968 4 13
+32 282773968 5 13
+32 446683627 1 10
+32 446683627 2 10
+32 446683627 3 10
+32 446683627 4 10
+32 446683627 5 10
+32 2843691041 1 15
+32 2843691041 2 15
+32 2843691041 3 15
+32 2843691041 4 15
+32 2843691041 5 15
+32 1191222343 1 8
+32 1191222343 2 8
+32 1191222343 3 8
+32 1191222343 4 8
+32 1191222343 5 8
+32 2016286435 1 10
+32 2016286435 2 10
+32 2016286435 3 10
+32 2016286435 4 10
+32 2016286435 5 10
+32 1893861518 1 5
+32 1893861518 2 5
+32 1893861518 3 5
+32 1893861518 4 5
+32 1893861518 5 5
+32 3977622147 1 12
+32 3977622147 2 12
+32 3977622147 3 12
+32 3977622147 4 12
+32 3977622147 5 12
+32 571267417 1 15
+32 571267417 2 15
+32 571267417 3 15
+32 571267417 4 15
+32 571267417 5 15
+32 2363239984 1 13
+32 2363239984 2 13
+32 2363239984 3 13
+32 2363239984 4 13
+32 2363239984 5 13
diff --git a/vdslib/src/tests/distribution/testdata/java_capacity.state b/vdslib/src/tests/distribution/testdata/java_capacity.state
new file mode 100644
index 00000000000..caa1aadf549
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/java_capacity.state
@@ -0,0 +1 @@
+distributor:20 storage:20 .3.c:3 .7.c:2.5 .12.c:1.5 \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/java_depth2.cfg b/vdslib/src/tests/distribution/testdata/java_depth2.cfg
new file mode 100644
index 00000000000..f22799ab574
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/java_depth2.cfg
@@ -0,0 +1,30 @@
+redundancy 3
+group[4]
+group[0].index "invalid"
+group[0].name "invalid"
+group[0].partitions 1|2|*
+group[0].nodes[0]
+group[1].index 1
+group[1].capacity 2.0
+group[1].name group1
+group[1].partitions *
+group[1].nodes[3]
+group[1].nodes[0].index 0
+group[1].nodes[1].index 1
+group[1].nodes[2].index 2
+group[2].index 2
+group[2].capacity 3.0
+group[2].name group2
+group[2].partitions *
+group[2].nodes[3]
+group[2].nodes[0].index 3
+group[2].nodes[1].index 4
+group[2].nodes[2].index 5
+group[3].index 3
+group[3].capacity 5.0
+group[3].name group3
+group[3].partitions *
+group[3].nodes[3]
+group[3].nodes[0].index 6
+group[3].nodes[1].index 7
+group[3].nodes[2].index 8
diff --git a/vdslib/src/tests/distribution/testdata/java_depth2.distribution b/vdslib/src/tests/distribution/testdata/java_depth2.distribution
new file mode 100644
index 00000000000..07792a8a2f3
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/java_depth2.distribution
@@ -0,0 +1,5373 @@
+0 0 1 6
+0 0 2 6
+0 0 3 6
+1 0 1 6
+1 0 2 6
+1 0 3 6
+1 1 1 0
+1 1 2 0
+1 1 3 0
+2 0 1 6
+2 0 2 6
+2 0 3 6
+2 1 1 0
+2 1 2 0
+2 1 3 0
+2 2 1 4
+2 2 2 4
+2 2 3 4
+2 3 1 8
+2 3 2 8
+2 3 3 8
+3 0 1 6
+3 0 2 6
+3 0 3 6
+3 1 1 0
+3 1 2 0
+3 1 3 0
+3 2 1 4
+3 2 2 4
+3 2 3 4
+3 3 1 8
+3 3 2 8
+3 3 3 8
+3 4 1 5
+3 4 2 5
+3 4 3 5
+3 5 1 8
+3 5 2 8
+3 5 3 8
+3 6 1 8
+3 6 2 8
+3 6 3 8
+3 7 1 3
+3 7 2 3
+3 7 3 3
+4 0 1 6
+4 0 2 6
+4 0 3 6
+4 1 1 0
+4 1 2 0
+4 1 3 0
+4 2 1 4
+4 2 2 4
+4 2 3 4
+4 3 1 8
+4 3 2 8
+4 3 3 8
+4 4 1 5
+4 4 2 5
+4 4 3 5
+4 5 1 8
+4 5 2 8
+4 5 3 8
+4 6 1 8
+4 6 2 8
+4 6 3 8
+4 7 1 3
+4 7 2 3
+4 7 3 3
+4 8 1 8
+4 8 2 8
+4 8 3 8
+4 9 1 3
+4 9 2 3
+4 9 3 3
+4 10 1 8
+4 10 2 8
+4 10 3 8
+4 11 1 5
+4 11 2 5
+4 11 3 5
+4 12 1 8
+4 12 2 8
+4 12 3 8
+4 13 1 8
+4 13 2 8
+4 13 3 8
+4 14 1 0
+4 14 2 0
+4 14 3 0
+4 15 1 8
+4 15 2 8
+4 15 3 8
+5 0 1 6
+5 0 2 6
+5 0 3 6
+5 1 1 0
+5 1 2 0
+5 1 3 0
+5 2 1 4
+5 2 2 4
+5 2 3 4
+5 3 1 8
+5 3 2 8
+5 3 3 8
+5 4 1 5
+5 4 2 5
+5 4 3 5
+5 5 1 8
+5 5 2 8
+5 5 3 8
+5 6 1 8
+5 6 2 8
+5 6 3 8
+5 7 1 3
+5 7 2 3
+5 7 3 3
+5 8 1 8
+5 8 2 8
+5 8 3 8
+5 9 1 3
+5 9 2 3
+5 9 3 3
+5 10 1 8
+5 10 2 8
+5 10 3 8
+5 11 1 5
+5 11 2 5
+5 11 3 5
+5 12 1 8
+5 12 2 8
+5 12 3 8
+5 13 1 8
+5 13 2 8
+5 13 3 8
+5 14 1 0
+5 14 2 0
+5 14 3 0
+5 15 1 8
+5 15 2 8
+5 15 3 8
+5 16 1 3
+5 16 2 3
+5 16 3 3
+5 17 1 7
+5 17 2 7
+5 17 3 7
+5 18 1 5
+5 18 2 5
+5 18 3 5
+5 19 1 1
+5 19 2 1
+5 19 3 1
+5 20 1 1
+5 20 2 1
+5 20 3 1
+5 21 1 8
+5 21 2 8
+5 21 3 8
+5 22 1 8
+5 22 2 8
+5 22 3 8
+5 23 1 5
+5 23 2 5
+5 23 3 5
+5 24 1 8
+5 24 2 8
+5 24 3 8
+5 25 1 4
+5 25 2 4
+5 25 3 4
+5 26 1 8
+5 26 2 8
+5 26 3 8
+5 27 1 8
+5 27 2 8
+5 27 3 8
+5 28 1 4
+5 28 2 4
+5 28 3 4
+5 29 1 8
+5 29 2 8
+5 29 3 8
+5 30 1 5
+5 30 2 5
+5 30 3 5
+5 31 1 8
+5 31 2 8
+5 31 3 8
+6 0 1 6
+6 0 2 6
+6 0 3 6
+6 1 1 0
+6 1 2 0
+6 1 3 0
+6 2 1 4
+6 2 2 4
+6 2 3 4
+6 3 1 8
+6 3 2 8
+6 3 3 8
+6 4 1 5
+6 4 2 5
+6 4 3 5
+6 5 1 8
+6 5 2 8
+6 5 3 8
+6 6 1 8
+6 6 2 8
+6 6 3 8
+6 7 1 3
+6 7 2 3
+6 7 3 3
+6 8 1 8
+6 8 2 8
+6 8 3 8
+6 9 1 3
+6 9 2 3
+6 9 3 3
+6 10 1 8
+6 10 2 8
+6 10 3 8
+6 11 1 5
+6 11 2 5
+6 11 3 5
+6 12 1 8
+6 12 2 8
+6 12 3 8
+6 13 1 8
+6 13 2 8
+6 13 3 8
+6 14 1 0
+6 14 2 0
+6 14 3 0
+6 15 1 8
+6 15 2 8
+6 15 3 8
+6 16 1 3
+6 16 2 3
+6 16 3 3
+6 17 1 7
+6 17 2 7
+6 17 3 7
+6 18 1 5
+6 18 2 5
+6 18 3 5
+6 19 1 1
+6 19 2 1
+6 19 3 1
+6 20 1 1
+6 20 2 1
+6 20 3 1
+6 21 1 8
+6 21 2 8
+6 21 3 8
+6 22 1 8
+6 22 2 8
+6 22 3 8
+6 23 1 5
+6 23 2 5
+6 23 3 5
+6 24 1 8
+6 24 2 8
+6 24 3 8
+6 25 1 4
+6 25 2 4
+6 25 3 4
+6 26 1 8
+6 26 2 8
+6 26 3 8
+6 27 1 8
+6 27 2 8
+6 27 3 8
+6 28 1 4
+6 28 2 4
+6 28 3 4
+6 29 1 8
+6 29 2 8
+6 29 3 8
+6 30 1 5
+6 30 2 5
+6 30 3 5
+6 31 1 8
+6 31 2 8
+6 31 3 8
+6 32 1 5
+6 32 2 5
+6 32 3 5
+6 33 1 8
+6 33 2 8
+6 33 3 8
+6 34 1 7
+6 34 2 7
+6 34 3 7
+6 35 1 7
+6 35 2 7
+6 35 3 7
+6 36 1 8
+6 36 2 8
+6 36 3 8
+6 37 1 5
+6 37 2 5
+6 37 3 5
+6 38 1 2
+6 38 2 2
+6 38 3 2
+6 39 1 4
+6 39 2 4
+6 39 3 4
+6 40 1 8
+6 40 2 8
+6 40 3 8
+6 41 1 8
+6 41 2 8
+6 41 3 8
+6 42 1 4
+6 42 2 4
+6 42 3 4
+6 43 1 1
+6 43 2 1
+6 43 3 1
+6 44 1 7
+6 44 2 7
+6 44 3 7
+6 45 1 6
+6 45 2 6
+6 45 3 6
+6 46 1 5
+6 46 2 5
+6 46 3 5
+6 47 1 7
+6 47 2 7
+6 47 3 7
+6 48 1 0
+6 48 2 0
+6 48 3 0
+6 49 1 8
+6 49 2 8
+6 49 3 8
+6 50 1 1
+6 50 2 1
+6 50 3 1
+6 51 1 4
+6 51 2 4
+6 51 3 4
+6 52 1 8
+6 52 2 8
+6 52 3 8
+6 53 1 5
+6 53 2 5
+6 53 3 5
+6 54 1 8
+6 54 2 8
+6 54 3 8
+6 55 1 1
+6 55 2 1
+6 55 3 1
+6 56 1 2
+6 56 2 2
+6 56 3 2
+6 57 1 6
+6 57 2 6
+6 57 3 6
+6 58 1 6
+6 58 2 6
+6 58 3 6
+6 59 1 6
+6 59 2 6
+6 59 3 6
+6 60 1 3
+6 60 2 3
+6 60 3 3
+6 61 1 2
+6 61 2 2
+6 61 3 2
+6 62 1 8
+6 62 2 8
+6 62 3 8
+6 63 1 8
+6 63 2 8
+6 63 3 8
+7 57 1 6
+7 57 2 6
+7 57 3 6
+7 93 1 5
+7 93 2 5
+7 93 3 5
+7 18 1 5
+7 18 2 5
+7 18 3 5
+7 93 1 5
+7 93 2 5
+7 93 3 5
+7 33 1 8
+7 33 2 8
+7 33 3 8
+7 95 1 5
+7 95 2 5
+7 95 3 5
+7 124 1 0
+7 124 2 0
+7 124 3 0
+7 101 1 2
+7 101 2 2
+7 101 3 2
+7 78 1 7
+7 78 2 7
+7 78 3 7
+7 105 1 8
+7 105 2 8
+7 105 3 8
+7 55 1 1
+7 55 2 1
+7 55 3 1
+7 105 1 8
+7 105 2 8
+7 105 3 8
+7 113 1 0
+7 113 2 0
+7 113 3 0
+7 38 1 2
+7 38 2 2
+7 38 3 2
+7 51 1 4
+7 51 2 4
+7 51 3 4
+7 39 1 4
+7 39 2 4
+7 39 3 4
+7 89 1 0
+7 89 2 0
+7 89 3 0
+7 4 1 5
+7 4 2 5
+7 4 3 5
+7 68 1 6
+7 68 2 6
+7 68 3 6
+7 96 1 6
+7 96 2 6
+7 96 3 6
+7 126 1 6
+7 126 2 6
+7 126 3 6
+7 54 1 8
+7 54 2 8
+7 54 3 8
+7 34 1 7
+7 34 2 7
+7 34 3 7
+7 89 1 0
+7 89 2 0
+7 89 3 0
+7 122 1 7
+7 122 2 7
+7 122 3 7
+7 53 1 5
+7 53 2 5
+7 53 3 5
+7 105 1 8
+7 105 2 8
+7 105 3 8
+7 90 1 8
+7 90 2 8
+7 90 3 8
+7 11 1 5
+7 11 2 5
+7 11 3 5
+7 59 1 6
+7 59 2 6
+7 59 3 6
+7 26 1 8
+7 26 2 8
+7 26 3 8
+7 50 1 1
+7 50 2 1
+7 50 3 1
+7 19 1 1
+7 19 2 1
+7 19 3 1
+7 70 1 4
+7 70 2 4
+7 70 3 4
+7 25 1 4
+7 25 2 4
+7 25 3 4
+7 48 1 0
+7 48 2 0
+7 48 3 0
+7 24 1 8
+7 24 2 8
+7 24 3 8
+7 27 1 8
+7 27 2 8
+7 27 3 8
+7 44 1 7
+7 44 2 7
+7 44 3 7
+7 44 1 7
+7 44 2 7
+7 44 3 7
+7 68 1 6
+7 68 2 6
+7 68 3 6
+7 65 1 5
+7 65 2 5
+7 65 3 5
+7 2 1 4
+7 2 2 4
+7 2 3 4
+7 124 1 0
+7 124 2 0
+7 124 3 0
+7 101 1 2
+7 101 2 2
+7 101 3 2
+7 2 1 4
+7 2 2 4
+7 2 3 4
+7 42 1 4
+7 42 2 4
+7 42 3 4
+7 127 1 6
+7 127 2 6
+7 127 3 6
+7 110 1 8
+7 110 2 8
+7 110 3 8
+7 109 1 3
+7 109 2 3
+7 109 3 3
+7 24 1 8
+7 24 2 8
+7 24 3 8
+7 22 1 8
+7 22 2 8
+7 22 3 8
+7 117 1 7
+7 117 2 7
+7 117 3 7
+7 87 1 8
+7 87 2 8
+7 87 3 8
+7 35 1 7
+7 35 2 7
+7 35 3 7
+7 37 1 5
+7 37 2 5
+7 37 3 5
+7 51 1 4
+7 51 2 4
+7 51 3 4
+7 85 1 8
+7 85 2 8
+7 85 3 8
+7 10 1 8
+7 10 2 8
+7 10 3 8
+7 23 1 5
+7 23 2 5
+7 23 3 5
+7 7 1 3
+7 7 2 3
+7 7 3 3
+7 67 1 3
+7 67 2 3
+7 67 3 3
+7 106 1 1
+7 106 2 1
+7 106 3 1
+7 88 1 5
+7 88 2 5
+7 88 3 5
+8 91 1 8
+8 91 2 8
+8 91 3 8
+8 237 1 3
+8 237 2 3
+8 237 3 3
+8 214 1 4
+8 214 2 4
+8 214 3 4
+8 65 1 5
+8 65 2 5
+8 65 3 5
+8 132 1 4
+8 132 2 4
+8 132 3 4
+8 211 1 6
+8 211 2 6
+8 211 3 6
+8 184 1 4
+8 184 2 4
+8 184 3 4
+8 171 1 5
+8 171 2 5
+8 171 3 5
+8 63 1 8
+8 63 2 8
+8 63 3 8
+8 179 1 3
+8 179 2 3
+8 179 3 3
+8 249 1 6
+8 249 2 6
+8 249 3 6
+8 102 1 3
+8 102 2 3
+8 102 3 3
+8 170 1 0
+8 170 2 0
+8 170 3 0
+8 199 1 7
+8 199 2 7
+8 199 3 7
+8 18 1 5
+8 18 2 5
+8 18 3 5
+8 147 1 3
+8 147 2 3
+8 147 3 3
+8 58 1 6
+8 58 2 6
+8 58 3 6
+8 185 1 2
+8 185 2 2
+8 185 3 2
+8 16 1 3
+8 16 2 3
+8 16 3 3
+8 9 1 3
+8 9 2 3
+8 9 3 3
+8 54 1 8
+8 54 2 8
+8 54 3 8
+8 44 1 7
+8 44 2 7
+8 44 3 7
+8 22 1 8
+8 22 2 8
+8 22 3 8
+8 212 1 7
+8 212 2 7
+8 212 3 7
+8 57 1 6
+8 57 2 6
+8 57 3 6
+8 51 1 4
+8 51 2 4
+8 51 3 4
+8 217 1 8
+8 217 2 8
+8 217 3 8
+8 176 1 8
+8 176 2 8
+8 176 3 8
+8 180 1 0
+8 180 2 0
+8 180 3 0
+8 216 1 3
+8 216 2 3
+8 216 3 3
+8 34 1 7
+8 34 2 7
+8 34 3 7
+8 146 1 5
+8 146 2 5
+8 146 3 5
+8 105 1 8
+8 105 2 8
+8 105 3 8
+8 151 1 5
+8 151 2 5
+8 151 3 5
+8 80 1 4
+8 80 2 4
+8 80 3 4
+8 32 1 5
+8 32 2 5
+8 32 3 5
+8 241 1 7
+8 241 2 7
+8 241 3 7
+8 224 1 7
+8 224 2 7
+8 224 3 7
+8 211 1 6
+8 211 2 6
+8 211 3 6
+8 52 1 8
+8 52 2 8
+8 52 3 8
+8 56 1 2
+8 56 2 2
+8 56 3 2
+8 152 1 0
+8 152 2 0
+8 152 3 0
+8 178 1 8
+8 178 2 8
+8 178 3 8
+8 93 1 5
+8 93 2 5
+8 93 3 5
+8 251 1 2
+8 251 2 2
+8 251 3 2
+8 152 1 0
+8 152 2 0
+8 152 3 0
+8 6 1 8
+8 6 2 8
+8 6 3 8
+8 93 1 5
+8 93 2 5
+8 93 3 5
+8 81 1 3
+8 81 2 3
+8 81 3 3
+8 45 1 6
+8 45 2 6
+8 45 3 6
+8 125 1 1
+8 125 2 1
+8 125 3 1
+8 172 1 6
+8 172 2 6
+8 172 3 6
+8 31 1 8
+8 31 2 8
+8 31 3 8
+8 150 1 8
+8 150 2 8
+8 150 3 8
+8 216 1 3
+8 216 2 3
+8 216 3 3
+8 243 1 0
+8 243 2 0
+8 243 3 0
+8 162 1 2
+8 162 2 2
+8 162 3 2
+8 138 1 7
+8 138 2 7
+8 138 3 7
+8 109 1 3
+8 109 2 3
+8 109 3 3
+8 146 1 5
+8 146 2 5
+8 146 3 5
+8 234 1 6
+8 234 2 6
+8 234 3 6
+8 175 1 0
+8 175 2 0
+8 175 3 0
+8 165 1 3
+8 165 2 3
+8 165 3 3
+8 28 1 4
+8 28 2 4
+8 28 3 4
+9 47 1 7
+9 47 2 7
+9 47 3 7
+9 163 1 6
+9 163 2 6
+9 163 3 6
+9 176 1 8
+9 176 2 8
+9 176 3 8
+9 59 1 6
+9 59 2 6
+9 59 3 6
+9 76 1 8
+9 76 2 8
+9 76 3 8
+9 260 1 4
+9 260 2 4
+9 260 3 4
+9 324 1 8
+9 324 2 8
+9 324 3 8
+9 160 1 5
+9 160 2 5
+9 160 3 5
+9 137 1 3
+9 137 2 3
+9 137 3 3
+9 476 1 7
+9 476 2 7
+9 476 3 7
+9 57 1 6
+9 57 2 6
+9 57 3 6
+9 204 1 1
+9 204 2 1
+9 204 3 1
+9 105 1 8
+9 105 2 8
+9 105 3 8
+9 307 1 8
+9 307 2 8
+9 307 3 8
+9 37 1 5
+9 37 2 5
+9 37 3 5
+9 297 1 8
+9 297 2 8
+9 297 3 8
+9 180 1 0
+9 180 2 0
+9 180 3 0
+9 503 1 6
+9 503 2 6
+9 503 3 6
+9 287 1 3
+9 287 2 3
+9 287 3 3
+9 325 1 1
+9 325 2 1
+9 325 3 1
+9 500 1 5
+9 500 2 5
+9 500 3 5
+9 119 1 1
+9 119 2 1
+9 119 3 1
+9 327 1 8
+9 327 2 8
+9 327 3 8
+9 83 1 1
+9 83 2 1
+9 83 3 1
+9 249 1 6
+9 249 2 6
+9 249 3 6
+9 230 1 3
+9 230 2 3
+9 230 3 3
+9 316 1 4
+9 316 2 4
+9 316 3 4
+9 424 1 7
+9 424 2 7
+9 424 3 7
+9 341 1 1
+9 341 2 1
+9 341 3 1
+9 478 1 4
+9 478 2 4
+9 478 3 4
+9 164 1 0
+9 164 2 0
+9 164 3 0
+9 319 1 5
+9 319 2 5
+9 319 3 5
+9 481 1 1
+9 481 2 1
+9 481 3 1
+9 218 1 7
+9 218 2 7
+9 218 3 7
+9 168 1 6
+9 168 2 6
+9 168 3 6
+9 54 1 8
+9 54 2 8
+9 54 3 8
+9 310 1 5
+9 310 2 5
+9 310 3 5
+9 186 1 6
+9 186 2 6
+9 186 3 6
+9 116 1 5
+9 116 2 5
+9 116 3 5
+9 335 1 5
+9 335 2 5
+9 335 3 5
+9 53 1 5
+9 53 2 5
+9 53 3 5
+9 67 1 3
+9 67 2 3
+9 67 3 3
+9 444 1 3
+9 444 2 3
+9 444 3 3
+9 368 1 4
+9 368 2 4
+9 368 3 4
+9 128 1 1
+9 128 2 1
+9 128 3 1
+9 157 1 1
+9 157 2 1
+9 157 3 1
+9 306 1 8
+9 306 2 8
+9 306 3 8
+9 35 1 7
+9 35 2 7
+9 35 3 7
+9 254 1 6
+9 254 2 6
+9 254 3 6
+9 467 1 7
+9 467 2 7
+9 467 3 7
+9 273 1 2
+9 273 2 2
+9 273 3 2
+9 23 1 5
+9 23 2 5
+9 23 3 5
+9 91 1 8
+9 91 2 8
+9 91 3 8
+9 342 1 7
+9 342 2 7
+9 342 3 7
+9 405 1 5
+9 405 2 5
+9 405 3 5
+9 413 1 7
+9 413 2 7
+9 413 3 7
+9 389 1 8
+9 389 2 8
+9 389 3 8
+9 123 1 4
+9 123 2 4
+9 123 3 4
+9 384 1 7
+9 384 2 7
+9 384 3 7
+9 299 1 8
+9 299 2 8
+9 299 3 8
+9 48 1 0
+9 48 2 0
+9 48 3 0
+9 248 1 6
+9 248 2 6
+9 248 3 6
+9 151 1 5
+9 151 2 5
+9 151 3 5
+9 477 1 4
+9 477 2 4
+9 477 3 4
+10 436 1 8
+10 436 2 8
+10 436 3 8
+10 128 1 1
+10 128 2 1
+10 128 3 1
+10 545 1 7
+10 545 2 7
+10 545 3 7
+10 332 1 8
+10 332 2 8
+10 332 3 8
+10 758 1 8
+10 758 2 8
+10 758 3 8
+10 625 1 8
+10 625 2 8
+10 625 3 8
+10 160 1 5
+10 160 2 5
+10 160 3 5
+10 194 1 6
+10 194 2 6
+10 194 3 6
+10 172 1 6
+10 172 2 6
+10 172 3 6
+10 866 1 7
+10 866 2 7
+10 866 3 7
+10 120 1 7
+10 120 2 7
+10 120 3 7
+10 923 1 2
+10 923 2 2
+10 923 3 2
+10 813 1 8
+10 813 2 8
+10 813 3 8
+10 493 1 1
+10 493 2 1
+10 493 3 1
+10 748 1 0
+10 748 2 0
+10 748 3 0
+10 104 1 7
+10 104 2 7
+10 104 3 7
+10 326 1 4
+10 326 2 4
+10 326 3 4
+10 573 1 8
+10 573 2 8
+10 573 3 8
+10 754 1 7
+10 754 2 7
+10 754 3 7
+10 146 1 5
+10 146 2 5
+10 146 3 5
+10 697 1 7
+10 697 2 7
+10 697 3 7
+10 150 1 8
+10 150 2 8
+10 150 3 8
+10 948 1 7
+10 948 2 7
+10 948 3 7
+10 726 1 0
+10 726 2 0
+10 726 3 0
+10 698 1 3
+10 698 2 3
+10 698 3 3
+10 974 1 1
+10 974 2 1
+10 974 3 1
+10 787 1 5
+10 787 2 5
+10 787 3 5
+10 449 1 5
+10 449 2 5
+10 449 3 5
+10 624 1 2
+10 624 2 2
+10 624 3 2
+10 972 1 6
+10 972 2 6
+10 972 3 6
+10 31 1 8
+10 31 2 8
+10 31 3 8
+10 568 1 6
+10 568 2 6
+10 568 3 6
+10 890 1 6
+10 890 2 6
+10 890 3 6
+10 16 1 3
+10 16 2 3
+10 16 3 3
+10 416 1 5
+10 416 2 5
+10 416 3 5
+10 499 1 6
+10 499 2 6
+10 499 3 6
+10 615 1 6
+10 615 2 6
+10 615 3 6
+10 555 1 1
+10 555 2 1
+10 555 3 1
+10 144 1 8
+10 144 2 8
+10 144 3 8
+10 509 1 3
+10 509 2 3
+10 509 3 3
+10 316 1 4
+10 316 2 4
+10 316 3 4
+10 66 1 1
+10 66 2 1
+10 66 3 1
+10 671 1 3
+10 671 2 3
+10 671 3 3
+10 310 1 5
+10 310 2 5
+10 310 3 5
+10 499 1 6
+10 499 2 6
+10 499 3 6
+10 911 1 6
+10 911 2 6
+10 911 3 6
+10 174 1 3
+10 174 2 3
+10 174 3 3
+10 721 1 3
+10 721 2 3
+10 721 3 3
+10 246 1 5
+10 246 2 5
+10 246 3 5
+10 736 1 8
+10 736 2 8
+10 736 3 8
+10 340 1 5
+10 340 2 5
+10 340 3 5
+10 214 1 4
+10 214 2 4
+10 214 3 4
+10 936 1 6
+10 936 2 6
+10 936 3 6
+10 278 1 1
+10 278 2 1
+10 278 3 1
+10 860 1 1
+10 860 2 1
+10 860 3 1
+10 673 1 7
+10 673 2 7
+10 673 3 7
+10 732 1 2
+10 732 2 2
+10 732 3 2
+10 936 1 6
+10 936 2 6
+10 936 3 6
+10 69 1 6
+10 69 2 6
+10 69 3 6
+10 865 1 1
+10 865 2 1
+10 865 3 1
+10 348 1 6
+10 348 2 6
+10 348 3 6
+10 285 1 2
+10 285 2 2
+10 285 3 2
+10 705 1 3
+10 705 2 3
+10 705 3 3
+10 154 1 8
+10 154 2 8
+10 154 3 8
+11 1671 1 0
+11 1671 2 0
+11 1671 3 0
+11 1334 1 1
+11 1334 2 1
+11 1334 3 1
+11 763 1 8
+11 763 2 8
+11 763 3 8
+11 1607 1 7
+11 1607 2 7
+11 1607 3 7
+11 1725 1 0
+11 1725 2 0
+11 1725 3 0
+11 162 1 2
+11 162 2 2
+11 162 3 2
+11 1068 1 4
+11 1068 2 4
+11 1068 3 4
+11 1207 1 6
+11 1207 2 6
+11 1207 3 6
+11 501 1 3
+11 501 2 3
+11 501 3 3
+11 1419 1 4
+11 1419 2 4
+11 1419 3 4
+11 440 1 8
+11 440 2 8
+11 440 3 8
+11 512 1 4
+11 512 2 4
+11 512 3 4
+11 1260 1 6
+11 1260 2 6
+11 1260 3 6
+11 1626 1 0
+11 1626 2 0
+11 1626 3 0
+11 1023 1 7
+11 1023 2 7
+11 1023 3 7
+11 510 1 1
+11 510 2 1
+11 510 3 1
+11 960 1 0
+11 960 2 0
+11 960 3 0
+11 1403 1 6
+11 1403 2 6
+11 1403 3 6
+11 1281 1 8
+11 1281 2 8
+11 1281 3 8
+11 1230 1 1
+11 1230 2 1
+11 1230 3 1
+11 631 1 8
+11 631 2 8
+11 631 3 8
+11 481 1 1
+11 481 2 1
+11 481 3 1
+11 229 1 6
+11 229 2 6
+11 229 3 6
+11 853 1 7
+11 853 2 7
+11 853 3 7
+11 1401 1 3
+11 1401 2 3
+11 1401 3 3
+11 896 1 3
+11 896 2 3
+11 896 3 3
+11 1654 1 3
+11 1654 2 3
+11 1654 3 3
+11 953 1 8
+11 953 2 8
+11 953 3 8
+11 530 1 4
+11 530 2 4
+11 530 3 4
+11 2002 1 4
+11 2002 2 4
+11 2002 3 4
+11 1953 1 5
+11 1953 2 5
+11 1953 3 5
+11 1509 1 8
+11 1509 2 8
+11 1509 3 8
+11 1778 1 7
+11 1778 2 7
+11 1778 3 7
+11 1619 1 6
+11 1619 2 6
+11 1619 3 6
+11 504 1 2
+11 504 2 2
+11 504 3 2
+11 9 1 3
+11 9 2 3
+11 9 3 3
+11 1196 1 7
+11 1196 2 7
+11 1196 3 7
+11 1285 1 8
+11 1285 2 8
+11 1285 3 8
+11 1842 1 7
+11 1842 2 7
+11 1842 3 7
+11 792 1 5
+11 792 2 5
+11 792 3 5
+11 1594 1 5
+11 1594 2 5
+11 1594 3 5
+11 1261 1 5
+11 1261 2 5
+11 1261 3 5
+11 1448 1 4
+11 1448 2 4
+11 1448 3 4
+11 1865 1 7
+11 1865 2 7
+11 1865 3 7
+11 375 1 6
+11 375 2 6
+11 375 3 6
+11 1684 1 0
+11 1684 2 0
+11 1684 3 0
+11 218 1 7
+11 218 2 7
+11 218 3 7
+11 151 1 5
+11 151 2 5
+11 151 3 5
+11 1956 1 8
+11 1956 2 8
+11 1956 3 8
+11 1670 1 7
+11 1670 2 7
+11 1670 3 7
+11 488 1 7
+11 488 2 7
+11 488 3 7
+11 833 1 3
+11 833 2 3
+11 833 3 3
+11 1508 1 8
+11 1508 2 8
+11 1508 3 8
+11 470 1 8
+11 470 2 8
+11 470 3 8
+11 26 1 8
+11 26 2 8
+11 26 3 8
+11 74 1 5
+11 74 2 5
+11 74 3 5
+11 1471 1 3
+11 1471 2 3
+11 1471 3 3
+11 665 1 5
+11 665 2 5
+11 665 3 5
+11 345 1 6
+11 345 2 6
+11 345 3 6
+11 506 1 7
+11 506 2 7
+11 506 3 7
+11 1443 1 2
+11 1443 2 2
+11 1443 3 2
+11 1126 1 3
+11 1126 2 3
+11 1126 3 3
+11 691 1 8
+11 691 2 8
+11 691 3 8
+11 91 1 8
+11 91 2 8
+11 91 3 8
+12 2730 1 2
+12 2730 2 2
+12 2730 3 2
+12 2246 1 6
+12 2246 2 6
+12 2246 3 6
+12 3903 1 7
+12 3903 2 7
+12 3903 3 7
+12 811 1 7
+12 811 2 7
+12 811 3 7
+12 3489 1 6
+12 3489 2 6
+12 3489 3 6
+12 918 1 6
+12 918 2 6
+12 918 3 6
+12 2536 1 6
+12 2536 2 6
+12 2536 3 6
+12 126 1 6
+12 126 2 6
+12 126 3 6
+12 102 1 3
+12 102 2 3
+12 102 3 3
+12 3157 1 8
+12 3157 2 8
+12 3157 3 8
+12 2042 1 1
+12 2042 2 1
+12 2042 3 1
+12 509 1 3
+12 509 2 3
+12 509 3 3
+12 1445 1 7
+12 1445 2 7
+12 1445 3 7
+12 1146 1 7
+12 1146 2 7
+12 1146 3 7
+12 1373 1 5
+12 1373 2 5
+12 1373 3 5
+12 1513 1 0
+12 1513 2 0
+12 1513 3 0
+12 3105 1 3
+12 3105 2 3
+12 3105 3 3
+12 2481 1 7
+12 2481 2 7
+12 2481 3 7
+12 1869 1 6
+12 1869 2 6
+12 1869 3 6
+12 1527 1 8
+12 1527 2 8
+12 1527 3 8
+12 3375 1 7
+12 3375 2 7
+12 3375 3 7
+12 2135 1 6
+12 2135 2 6
+12 2135 3 6
+12 729 1 7
+12 729 2 7
+12 729 3 7
+12 464 1 4
+12 464 2 4
+12 464 3 4
+12 2872 1 7
+12 2872 2 7
+12 2872 3 7
+12 3583 1 8
+12 3583 2 8
+12 3583 3 8
+12 869 1 2
+12 869 2 2
+12 869 3 2
+12 2447 1 6
+12 2447 2 6
+12 2447 3 6
+12 59 1 6
+12 59 2 6
+12 59 3 6
+12 3055 1 7
+12 3055 2 7
+12 3055 3 7
+12 296 1 0
+12 296 2 0
+12 296 3 0
+12 2118 1 3
+12 2118 2 3
+12 2118 3 3
+12 3144 1 8
+12 3144 2 8
+12 3144 3 8
+12 2467 1 6
+12 2467 2 6
+12 2467 3 6
+12 1967 1 8
+12 1967 2 8
+12 1967 3 8
+12 3705 1 2
+12 3705 2 2
+12 3705 3 2
+12 1030 1 6
+12 1030 2 6
+12 1030 3 6
+12 1865 1 7
+12 1865 2 7
+12 1865 3 7
+12 3160 1 4
+12 3160 2 4
+12 3160 3 4
+12 3232 1 3
+12 3232 2 3
+12 3232 3 3
+12 3886 1 3
+12 3886 2 3
+12 3886 3 3
+12 68 1 6
+12 68 2 6
+12 68 3 6
+12 1240 1 4
+12 1240 2 4
+12 1240 3 4
+12 3498 1 5
+12 3498 2 5
+12 3498 3 5
+12 1805 1 0
+12 1805 2 0
+12 1805 3 0
+12 3498 1 5
+12 3498 2 5
+12 3498 3 5
+12 3510 1 8
+12 3510 2 8
+12 3510 3 8
+12 373 1 5
+12 373 2 5
+12 373 3 5
+12 1286 1 8
+12 1286 2 8
+12 1286 3 8
+12 2246 1 6
+12 2246 2 6
+12 2246 3 6
+12 205 1 7
+12 205 2 7
+12 205 3 7
+12 1879 1 0
+12 1879 2 0
+12 1879 3 0
+12 270 1 8
+12 270 2 8
+12 270 3 8
+12 3478 1 6
+12 3478 2 6
+12 3478 3 6
+12 3022 1 8
+12 3022 2 8
+12 3022 3 8
+12 2200 1 0
+12 2200 2 0
+12 2200 3 0
+12 46 1 5
+12 46 2 5
+12 46 3 5
+12 3405 1 8
+12 3405 2 8
+12 3405 3 8
+12 1724 1 8
+12 1724 2 8
+12 1724 3 8
+12 757 1 8
+12 757 2 8
+12 757 3 8
+12 773 1 2
+12 773 2 2
+12 773 3 2
+12 211 1 6
+12 211 2 6
+12 211 3 6
+12 2670 1 8
+12 2670 2 8
+12 2670 3 8
+12 799 1 7
+12 799 2 7
+12 799 3 7
+13 893 1 3
+13 893 2 3
+13 893 3 3
+13 380 1 7
+13 380 2 7
+13 380 3 7
+13 4122 1 6
+13 4122 2 6
+13 4122 3 6
+13 5157 1 1
+13 5157 2 1
+13 5157 3 1
+13 5480 1 1
+13 5480 2 1
+13 5480 3 1
+13 5574 1 3
+13 5574 2 3
+13 5574 3 3
+13 2420 1 3
+13 2420 2 3
+13 2420 3 3
+13 7282 1 3
+13 7282 2 3
+13 7282 3 3
+13 4528 1 1
+13 4528 2 1
+13 4528 3 1
+13 637 1 3
+13 637 2 3
+13 637 3 3
+13 2363 1 7
+13 2363 2 7
+13 2363 3 7
+13 99 1 6
+13 99 2 6
+13 99 3 6
+13 1892 1 1
+13 1892 2 1
+13 1892 3 1
+13 231 1 7
+13 231 2 7
+13 231 3 7
+13 2672 1 2
+13 2672 2 2
+13 2672 3 2
+13 4991 1 7
+13 4991 2 7
+13 4991 3 7
+13 2715 1 8
+13 2715 2 8
+13 2715 3 8
+13 239 1 0
+13 239 2 0
+13 239 3 0
+13 6492 1 7
+13 6492 2 7
+13 6492 3 7
+13 1587 1 8
+13 1587 2 8
+13 1587 3 8
+13 4333 1 5
+13 4333 2 5
+13 4333 3 5
+13 6561 1 5
+13 6561 2 5
+13 6561 3 5
+13 6154 1 5
+13 6154 2 5
+13 6154 3 5
+13 7759 1 5
+13 7759 2 5
+13 7759 3 5
+13 7672 1 0
+13 7672 2 0
+13 7672 3 0
+13 2481 1 7
+13 2481 2 7
+13 2481 3 7
+13 4808 1 6
+13 4808 2 6
+13 4808 3 6
+13 8071 1 3
+13 8071 2 3
+13 8071 3 3
+13 8156 1 6
+13 8156 2 6
+13 8156 3 6
+13 2037 1 8
+13 2037 2 8
+13 2037 3 8
+13 1194 1 4
+13 1194 2 4
+13 1194 3 4
+13 1011 1 7
+13 1011 2 7
+13 1011 3 7
+13 7104 1 8
+13 7104 2 8
+13 7104 3 8
+13 999 1 8
+13 999 2 8
+13 999 3 8
+13 3079 1 6
+13 3079 2 6
+13 3079 3 6
+13 1167 1 1
+13 1167 2 1
+13 1167 3 1
+13 2635 1 6
+13 2635 2 6
+13 2635 3 6
+13 5668 1 0
+13 5668 2 0
+13 5668 3 0
+13 3834 1 6
+13 3834 2 6
+13 3834 3 6
+13 4540 1 5
+13 4540 2 5
+13 4540 3 5
+13 1067 1 8
+13 1067 2 8
+13 1067 3 8
+13 239 1 0
+13 239 2 0
+13 239 3 0
+13 4066 1 7
+13 4066 2 7
+13 4066 3 7
+13 7101 1 8
+13 7101 2 8
+13 7101 3 8
+13 7826 1 2
+13 7826 2 2
+13 7826 3 2
+13 174 1 3
+13 174 2 3
+13 174 3 3
+13 4578 1 7
+13 4578 2 7
+13 4578 3 7
+13 2875 1 1
+13 2875 2 1
+13 2875 3 1
+13 6067 1 6
+13 6067 2 6
+13 6067 3 6
+13 3180 1 8
+13 3180 2 8
+13 3180 3 8
+13 3426 1 3
+13 3426 2 3
+13 3426 3 3
+13 2498 1 4
+13 2498 2 4
+13 2498 3 4
+13 4938 1 3
+13 4938 2 3
+13 4938 3 3
+13 1622 1 5
+13 1622 2 5
+13 1622 3 5
+13 5260 1 0
+13 5260 2 0
+13 5260 3 0
+13 6721 1 5
+13 6721 2 5
+13 6721 3 5
+13 1809 1 7
+13 1809 2 7
+13 1809 3 7
+13 7230 1 2
+13 7230 2 2
+13 7230 3 2
+13 2000 1 1
+13 2000 2 1
+13 2000 3 1
+13 398 1 6
+13 398 2 6
+13 398 3 6
+13 5964 1 7
+13 5964 2 7
+13 5964 3 7
+13 6171 1 6
+13 6171 2 6
+13 6171 3 6
+13 6752 1 6
+13 6752 2 6
+13 6752 3 6
+13 7904 1 6
+13 7904 2 6
+13 7904 3 6
+14 2306 1 3
+14 2306 2 3
+14 2306 3 3
+14 1881 1 6
+14 1881 2 6
+14 1881 3 6
+14 11659 1 4
+14 11659 2 4
+14 11659 3 4
+14 12598 1 8
+14 12598 2 8
+14 12598 3 8
+14 15891 1 2
+14 15891 2 2
+14 15891 3 2
+14 7988 1 6
+14 7988 2 6
+14 7988 3 6
+14 2768 1 2
+14 2768 2 2
+14 2768 3 2
+14 2197 1 6
+14 2197 2 6
+14 2197 3 6
+14 15826 1 7
+14 15826 2 7
+14 15826 3 7
+14 4100 1 8
+14 4100 2 8
+14 4100 3 8
+14 5497 1 2
+14 5497 2 2
+14 5497 3 2
+14 1329 1 2
+14 1329 2 2
+14 1329 3 2
+14 4648 1 4
+14 4648 2 4
+14 4648 3 4
+14 11168 1 3
+14 11168 2 3
+14 11168 3 3
+14 2871 1 6
+14 2871 2 6
+14 2871 3 6
+14 6846 1 2
+14 6846 2 2
+14 6846 3 2
+14 7982 1 7
+14 7982 2 7
+14 7982 3 7
+14 2869 1 3
+14 2869 2 3
+14 2869 3 3
+14 13103 1 7
+14 13103 2 7
+14 13103 3 7
+14 9600 1 0
+14 9600 2 0
+14 9600 3 0
+14 13746 1 0
+14 13746 2 0
+14 13746 3 0
+14 9665 1 7
+14 9665 2 7
+14 9665 3 7
+14 6264 1 7
+14 6264 2 7
+14 6264 3 7
+14 10450 1 8
+14 10450 2 8
+14 10450 3 8
+14 13753 1 2
+14 13753 2 2
+14 13753 3 2
+14 13977 1 3
+14 13977 2 3
+14 13977 3 3
+14 5279 1 7
+14 5279 2 7
+14 5279 3 7
+14 7584 1 8
+14 7584 2 8
+14 7584 3 8
+14 247 1 3
+14 247 2 3
+14 247 3 3
+14 13284 1 4
+14 13284 2 4
+14 13284 3 4
+14 10789 1 3
+14 10789 2 3
+14 10789 3 3
+14 4332 1 2
+14 4332 2 2
+14 4332 3 2
+14 15705 1 8
+14 15705 2 8
+14 15705 3 8
+14 5405 1 1
+14 5405 2 1
+14 5405 3 1
+14 12031 1 7
+14 12031 2 7
+14 12031 3 7
+14 4684 1 6
+14 4684 2 6
+14 4684 3 6
+14 10107 1 8
+14 10107 2 8
+14 10107 3 8
+14 10645 1 8
+14 10645 2 8
+14 10645 3 8
+14 1814 1 7
+14 1814 2 7
+14 1814 3 7
+14 12906 1 0
+14 12906 2 0
+14 12906 3 0
+14 13619 1 7
+14 13619 2 7
+14 13619 3 7
+14 16110 1 6
+14 16110 2 6
+14 16110 3 6
+14 11973 1 3
+14 11973 2 3
+14 11973 3 3
+14 4483 1 8
+14 4483 2 8
+14 4483 3 8
+14 2052 1 1
+14 2052 2 1
+14 2052 3 1
+14 6049 1 6
+14 6049 2 6
+14 6049 3 6
+14 5470 1 4
+14 5470 2 4
+14 5470 3 4
+14 15849 1 7
+14 15849 2 7
+14 15849 3 7
+14 12203 1 0
+14 12203 2 0
+14 12203 3 0
+14 12665 1 8
+14 12665 2 8
+14 12665 3 8
+14 1957 1 3
+14 1957 2 3
+14 1957 3 3
+14 8833 1 6
+14 8833 2 6
+14 8833 3 6
+14 15511 1 3
+14 15511 2 3
+14 15511 3 3
+14 7190 1 6
+14 7190 2 6
+14 7190 3 6
+14 10835 1 4
+14 10835 2 4
+14 10835 3 4
+14 1350 1 7
+14 1350 2 7
+14 1350 3 7
+14 8808 1 5
+14 8808 2 5
+14 8808 3 5
+14 8043 1 4
+14 8043 2 4
+14 8043 3 4
+14 1172 1 1
+14 1172 2 1
+14 1172 3 1
+14 5572 1 7
+14 5572 2 7
+14 5572 3 7
+14 10871 1 1
+14 10871 2 1
+14 10871 3 1
+14 12865 1 6
+14 12865 2 6
+14 12865 3 6
+14 6793 1 3
+14 6793 2 3
+14 6793 3 3
+14 2973 1 8
+14 2973 2 8
+14 2973 3 8
+15 20950 1 7
+15 20950 2 7
+15 20950 3 7
+15 4112 1 6
+15 4112 2 6
+15 4112 3 6
+15 20069 1 6
+15 20069 2 6
+15 20069 3 6
+15 21040 1 5
+15 21040 2 5
+15 21040 3 5
+15 1498 1 0
+15 1498 2 0
+15 1498 3 0
+15 4453 1 0
+15 4453 2 0
+15 4453 3 0
+15 27228 1 3
+15 27228 2 3
+15 27228 3 3
+15 9353 1 6
+15 9353 2 6
+15 9353 3 6
+15 12060 1 7
+15 12060 2 7
+15 12060 3 7
+15 30253 1 6
+15 30253 2 6
+15 30253 3 6
+15 9914 1 8
+15 9914 2 8
+15 9914 3 8
+15 9111 1 7
+15 9111 2 7
+15 9111 3 7
+15 9191 1 5
+15 9191 2 5
+15 9191 3 5
+15 2061 1 6
+15 2061 2 6
+15 2061 3 6
+15 16458 1 5
+15 16458 2 5
+15 16458 3 5
+15 14420 1 4
+15 14420 2 4
+15 14420 3 4
+15 11687 1 4
+15 11687 2 4
+15 11687 3 4
+15 12915 1 0
+15 12915 2 0
+15 12915 3 0
+15 30014 1 5
+15 30014 2 5
+15 30014 3 5
+15 17852 1 2
+15 17852 2 2
+15 17852 3 2
+15 18801 1 1
+15 18801 2 1
+15 18801 3 1
+15 30476 1 6
+15 30476 2 6
+15 30476 3 6
+15 19880 1 6
+15 19880 2 6
+15 19880 3 6
+15 25937 1 7
+15 25937 2 7
+15 25937 3 7
+15 30840 1 3
+15 30840 2 3
+15 30840 3 3
+15 29260 1 4
+15 29260 2 4
+15 29260 3 4
+15 29698 1 0
+15 29698 2 0
+15 29698 3 0
+15 13207 1 4
+15 13207 2 4
+15 13207 3 4
+15 8345 1 1
+15 8345 2 1
+15 8345 3 1
+15 28649 1 8
+15 28649 2 8
+15 28649 3 8
+15 7591 1 6
+15 7591 2 6
+15 7591 3 6
+15 11417 1 4
+15 11417 2 4
+15 11417 3 4
+15 31952 1 7
+15 31952 2 7
+15 31952 3 7
+15 3936 1 3
+15 3936 2 3
+15 3936 3 3
+15 855 1 7
+15 855 2 7
+15 855 3 7
+15 6242 1 7
+15 6242 2 7
+15 6242 3 7
+15 7617 1 5
+15 7617 2 5
+15 7617 3 5
+15 30831 1 3
+15 30831 2 3
+15 30831 3 3
+15 27063 1 8
+15 27063 2 8
+15 27063 3 8
+15 1925 1 2
+15 1925 2 2
+15 1925 3 2
+15 31280 1 0
+15 31280 2 0
+15 31280 3 0
+15 8089 1 7
+15 8089 2 7
+15 8089 3 7
+15 14799 1 4
+15 14799 2 4
+15 14799 3 4
+15 24470 1 7
+15 24470 2 7
+15 24470 3 7
+15 3977 1 4
+15 3977 2 4
+15 3977 3 4
+15 6822 1 0
+15 6822 2 0
+15 6822 3 0
+15 10634 1 8
+15 10634 2 8
+15 10634 3 8
+15 30639 1 8
+15 30639 2 8
+15 30639 3 8
+15 4697 1 5
+15 4697 2 5
+15 4697 3 5
+15 1311 1 1
+15 1311 2 1
+15 1311 3 1
+15 29753 1 3
+15 29753 2 3
+15 29753 3 3
+15 17644 1 6
+15 17644 2 6
+15 17644 3 6
+15 11986 1 7
+15 11986 2 7
+15 11986 3 7
+15 29910 1 8
+15 29910 2 8
+15 29910 3 8
+15 8977 1 1
+15 8977 2 1
+15 8977 3 1
+15 5871 1 8
+15 5871 2 8
+15 5871 3 8
+15 22859 1 6
+15 22859 2 6
+15 22859 3 6
+15 32348 1 8
+15 32348 2 8
+15 32348 3 8
+15 26024 1 8
+15 26024 2 8
+15 26024 3 8
+15 25693 1 0
+15 25693 2 0
+15 25693 3 0
+15 11966 1 4
+15 11966 2 4
+15 11966 3 4
+15 18826 1 8
+15 18826 2 8
+15 18826 3 8
+15 31356 1 6
+15 31356 2 6
+15 31356 3 6
+15 10078 1 0
+15 10078 2 0
+15 10078 3 0
+16 58244 1 7
+16 58244 2 7
+16 58244 3 7
+16 25812 1 1
+16 25812 2 1
+16 25812 3 1
+16 5981 1 6
+16 5981 2 6
+16 5981 3 6
+16 38854 1 7
+16 38854 2 7
+16 38854 3 7
+16 29656 1 8
+16 29656 2 8
+16 29656 3 8
+16 50754 1 4
+16 50754 2 4
+16 50754 3 4
+16 5784 1 7
+16 5784 2 7
+16 5784 3 7
+16 61887 1 8
+16 61887 2 8
+16 61887 3 8
+16 48214 1 1
+16 48214 2 1
+16 48214 3 1
+16 12266 1 2
+16 12266 2 2
+16 12266 3 2
+16 38129 1 3
+16 38129 2 3
+16 38129 3 3
+16 28380 1 8
+16 28380 2 8
+16 28380 3 8
+16 50376 1 6
+16 50376 2 6
+16 50376 3 6
+16 51343 1 6
+16 51343 2 6
+16 51343 3 6
+16 10060 1 3
+16 10060 2 3
+16 10060 3 3
+16 6542 1 2
+16 6542 2 2
+16 6542 3 2
+16 9936 1 8
+16 9936 2 8
+16 9936 3 8
+16 52971 1 6
+16 52971 2 6
+16 52971 3 6
+16 48546 1 3
+16 48546 2 3
+16 48546 3 3
+16 8054 1 8
+16 8054 2 8
+16 8054 3 8
+16 62559 1 8
+16 62559 2 8
+16 62559 3 8
+16 9259 1 6
+16 9259 2 6
+16 9259 3 6
+16 29059 1 1
+16 29059 2 1
+16 29059 3 1
+16 33772 1 5
+16 33772 2 5
+16 33772 3 5
+16 60991 1 4
+16 60991 2 4
+16 60991 3 4
+16 42607 1 6
+16 42607 2 6
+16 42607 3 6
+16 42127 1 4
+16 42127 2 4
+16 42127 3 4
+16 41593 1 8
+16 41593 2 8
+16 41593 3 8
+16 2699 1 8
+16 2699 2 8
+16 2699 3 8
+16 23372 1 3
+16 23372 2 3
+16 23372 3 3
+16 28412 1 1
+16 28412 2 1
+16 28412 3 1
+16 33117 1 1
+16 33117 2 1
+16 33117 3 1
+16 19250 1 3
+16 19250 2 3
+16 19250 3 3
+16 27209 1 5
+16 27209 2 5
+16 27209 3 5
+16 24083 1 8
+16 24083 2 8
+16 24083 3 8
+16 62474 1 0
+16 62474 2 0
+16 62474 3 0
+16 58487 1 2
+16 58487 2 2
+16 58487 3 2
+16 59237 1 7
+16 59237 2 7
+16 59237 3 7
+16 33459 1 8
+16 33459 2 8
+16 33459 3 8
+16 36262 1 3
+16 36262 2 3
+16 36262 3 3
+16 45939 1 2
+16 45939 2 2
+16 45939 3 2
+16 28047 1 5
+16 28047 2 5
+16 28047 3 5
+16 53197 1 8
+16 53197 2 8
+16 53197 3 8
+16 25485 1 8
+16 25485 2 8
+16 25485 3 8
+16 1170 1 3
+16 1170 2 3
+16 1170 3 3
+16 35117 1 0
+16 35117 2 0
+16 35117 3 0
+16 51430 1 8
+16 51430 2 8
+16 51430 3 8
+16 40909 1 8
+16 40909 2 8
+16 40909 3 8
+16 43538 1 4
+16 43538 2 4
+16 43538 3 4
+16 62102 1 7
+16 62102 2 7
+16 62102 3 7
+16 32920 1 8
+16 32920 2 8
+16 32920 3 8
+16 58281 1 2
+16 58281 2 2
+16 58281 3 2
+16 25223 1 1
+16 25223 2 1
+16 25223 3 1
+16 39064 1 3
+16 39064 2 3
+16 39064 3 3
+16 59153 1 2
+16 59153 2 2
+16 59153 3 2
+16 31255 1 4
+16 31255 2 4
+16 31255 3 4
+16 36698 1 1
+16 36698 2 1
+16 36698 3 1
+16 31474 1 7
+16 31474 2 7
+16 31474 3 7
+16 26770 1 8
+16 26770 2 8
+16 26770 3 8
+16 23106 1 8
+16 23106 2 8
+16 23106 3 8
+16 15173 1 7
+16 15173 2 7
+16 15173 3 7
+16 21723 1 4
+16 21723 2 4
+16 21723 3 4
+16 56305 1 8
+16 56305 2 8
+16 56305 3 8
+16 64008 1 1
+16 64008 2 1
+16 64008 3 1
+17 93272 1 3
+17 93272 2 3
+17 93272 3 3
+17 11659 1 4
+17 11659 2 4
+17 11659 3 4
+17 96311 1 5
+17 96311 2 5
+17 96311 3 5
+17 63681 1 5
+17 63681 2 5
+17 63681 3 5
+17 80799 1 5
+17 80799 2 5
+17 80799 3 5
+17 63603 1 1
+17 63603 2 1
+17 63603 3 1
+17 112164 1 8
+17 112164 2 8
+17 112164 3 8
+17 19891 1 6
+17 19891 2 6
+17 19891 3 6
+17 44447 1 5
+17 44447 2 5
+17 44447 3 5
+17 71186 1 8
+17 71186 2 8
+17 71186 3 8
+17 91697 1 1
+17 91697 2 1
+17 91697 3 1
+17 68930 1 7
+17 68930 2 7
+17 68930 3 7
+17 22151 1 5
+17 22151 2 5
+17 22151 3 5
+17 75004 1 1
+17 75004 2 1
+17 75004 3 1
+17 89182 1 0
+17 89182 2 0
+17 89182 3 0
+17 14115 1 6
+17 14115 2 6
+17 14115 3 6
+17 13641 1 2
+17 13641 2 2
+17 13641 3 2
+17 13865 1 1
+17 13865 2 1
+17 13865 3 1
+17 81842 1 0
+17 81842 2 0
+17 81842 3 0
+17 98226 1 3
+17 98226 2 3
+17 98226 3 3
+17 51230 1 1
+17 51230 2 1
+17 51230 3 1
+17 13686 1 5
+17 13686 2 5
+17 13686 3 5
+17 91828 1 5
+17 91828 2 5
+17 91828 3 5
+17 114795 1 4
+17 114795 2 4
+17 114795 3 4
+17 12543 1 7
+17 12543 2 7
+17 12543 3 7
+17 57890 1 7
+17 57890 2 7
+17 57890 3 7
+17 115698 1 3
+17 115698 2 3
+17 115698 3 3
+17 63601 1 7
+17 63601 2 7
+17 63601 3 7
+17 92716 1 0
+17 92716 2 0
+17 92716 3 0
+17 87889 1 7
+17 87889 2 7
+17 87889 3 7
+17 123518 1 0
+17 123518 2 0
+17 123518 3 0
+17 122122 1 5
+17 122122 2 5
+17 122122 3 5
+17 101033 1 3
+17 101033 2 3
+17 101033 3 3
+17 9357 1 3
+17 9357 2 3
+17 9357 3 3
+17 127595 1 6
+17 127595 2 6
+17 127595 3 6
+17 64032 1 6
+17 64032 2 6
+17 64032 3 6
+17 72380 1 1
+17 72380 2 1
+17 72380 3 1
+17 128576 1 7
+17 128576 2 7
+17 128576 3 7
+17 58709 1 6
+17 58709 2 6
+17 58709 3 6
+17 90818 1 3
+17 90818 2 3
+17 90818 3 3
+17 96369 1 5
+17 96369 2 5
+17 96369 3 5
+17 52794 1 7
+17 52794 2 7
+17 52794 3 7
+17 105174 1 7
+17 105174 2 7
+17 105174 3 7
+17 61857 1 4
+17 61857 2 4
+17 61857 3 4
+17 19478 1 8
+17 19478 2 8
+17 19478 3 8
+17 117809 1 8
+17 117809 2 8
+17 117809 3 8
+17 72978 1 7
+17 72978 2 7
+17 72978 3 7
+17 6547 1 0
+17 6547 2 0
+17 6547 3 0
+17 68799 1 3
+17 68799 2 3
+17 68799 3 3
+17 99900 1 8
+17 99900 2 8
+17 99900 3 8
+17 126252 1 3
+17 126252 2 3
+17 126252 3 3
+17 83476 1 5
+17 83476 2 5
+17 83476 3 5
+17 38083 1 8
+17 38083 2 8
+17 38083 3 8
+17 61784 1 8
+17 61784 2 8
+17 61784 3 8
+17 24526 1 7
+17 24526 2 7
+17 24526 3 7
+17 117696 1 3
+17 117696 2 3
+17 117696 3 3
+17 50749 1 5
+17 50749 2 5
+17 50749 3 5
+17 55779 1 5
+17 55779 2 5
+17 55779 3 5
+17 2470 1 8
+17 2470 2 8
+17 2470 3 8
+17 26842 1 8
+17 26842 2 8
+17 26842 3 8
+17 16268 1 8
+17 16268 2 8
+17 16268 3 8
+17 125988 1 0
+17 125988 2 0
+17 125988 3 0
+17 15331 1 6
+17 15331 2 6
+17 15331 3 6
+17 87497 1 8
+17 87497 2 8
+17 87497 3 8
+18 250333 1 8
+18 250333 2 8
+18 250333 3 8
+18 250728 1 0
+18 250728 2 0
+18 250728 3 0
+18 218536 1 2
+18 218536 2 2
+18 218536 3 2
+18 251345 1 8
+18 251345 2 8
+18 251345 3 8
+18 123978 1 8
+18 123978 2 8
+18 123978 3 8
+18 25057 1 7
+18 25057 2 7
+18 25057 3 7
+18 55168 1 6
+18 55168 2 6
+18 55168 3 6
+18 14806 1 6
+18 14806 2 6
+18 14806 3 6
+18 252354 1 6
+18 252354 2 6
+18 252354 3 6
+18 25497 1 5
+18 25497 2 5
+18 25497 3 5
+18 62064 1 0
+18 62064 2 0
+18 62064 3 0
+18 209425 1 1
+18 209425 2 1
+18 209425 3 1
+18 41291 1 3
+18 41291 2 3
+18 41291 3 3
+18 135093 1 5
+18 135093 2 5
+18 135093 3 5
+18 245030 1 8
+18 245030 2 8
+18 245030 3 8
+18 56931 1 8
+18 56931 2 8
+18 56931 3 8
+18 2524 1 2
+18 2524 2 2
+18 2524 3 2
+18 196720 1 8
+18 196720 2 8
+18 196720 3 8
+18 244100 1 4
+18 244100 2 4
+18 244100 3 4
+18 220927 1 6
+18 220927 2 6
+18 220927 3 6
+18 216291 1 4
+18 216291 2 4
+18 216291 3 4
+18 131478 1 6
+18 131478 2 6
+18 131478 3 6
+18 34594 1 8
+18 34594 2 8
+18 34594 3 8
+18 199406 1 4
+18 199406 2 4
+18 199406 3 4
+18 26816 1 4
+18 26816 2 4
+18 26816 3 4
+18 12041 1 1
+18 12041 2 1
+18 12041 3 1
+18 91593 1 5
+18 91593 2 5
+18 91593 3 5
+18 194186 1 6
+18 194186 2 6
+18 194186 3 6
+18 150343 1 6
+18 150343 2 6
+18 150343 3 6
+18 222016 1 3
+18 222016 2 3
+18 222016 3 3
+18 100345 1 6
+18 100345 2 6
+18 100345 3 6
+18 248323 1 3
+18 248323 2 3
+18 248323 3 3
+18 248898 1 3
+18 248898 2 3
+18 248898 3 3
+18 259523 1 7
+18 259523 2 7
+18 259523 3 7
+18 13668 1 4
+18 13668 2 4
+18 13668 3 4
+18 190429 1 7
+18 190429 2 7
+18 190429 3 7
+18 227309 1 6
+18 227309 2 6
+18 227309 3 6
+18 248240 1 7
+18 248240 2 7
+18 248240 3 7
+18 179569 1 5
+18 179569 2 5
+18 179569 3 5
+18 254832 1 3
+18 254832 2 3
+18 254832 3 3
+18 141688 1 7
+18 141688 2 7
+18 141688 3 7
+18 44089 1 3
+18 44089 2 3
+18 44089 3 3
+18 145850 1 4
+18 145850 2 4
+18 145850 3 4
+18 149351 1 7
+18 149351 2 7
+18 149351 3 7
+18 161161 1 6
+18 161161 2 6
+18 161161 3 6
+18 804 1 6
+18 804 2 6
+18 804 3 6
+18 204942 1 0
+18 204942 2 0
+18 204942 3 0
+18 109633 1 6
+18 109633 2 6
+18 109633 3 6
+18 189623 1 6
+18 189623 2 6
+18 189623 3 6
+18 117578 1 1
+18 117578 2 1
+18 117578 3 1
+18 42863 1 8
+18 42863 2 8
+18 42863 3 8
+18 138963 1 0
+18 138963 2 0
+18 138963 3 0
+18 65040 1 1
+18 65040 2 1
+18 65040 3 1
+18 59160 1 4
+18 59160 2 4
+18 59160 3 4
+18 128405 1 5
+18 128405 2 5
+18 128405 3 5
+18 186053 1 6
+18 186053 2 6
+18 186053 3 6
+18 205204 1 8
+18 205204 2 8
+18 205204 3 8
+18 179473 1 4
+18 179473 2 4
+18 179473 3 4
+18 206442 1 7
+18 206442 2 7
+18 206442 3 7
+18 81168 1 5
+18 81168 2 5
+18 81168 3 5
+18 209591 1 8
+18 209591 2 8
+18 209591 3 8
+18 9801 1 0
+18 9801 2 0
+18 9801 3 0
+18 7180 1 6
+18 7180 2 6
+18 7180 3 6
+18 148102 1 5
+18 148102 2 5
+18 148102 3 5
+19 285360 1 4
+19 285360 2 4
+19 285360 3 4
+19 39966 1 7
+19 39966 2 7
+19 39966 3 7
+19 439938 1 6
+19 439938 2 6
+19 439938 3 6
+19 276172 1 6
+19 276172 2 6
+19 276172 3 6
+19 371729 1 4
+19 371729 2 4
+19 371729 3 4
+19 168977 1 3
+19 168977 2 3
+19 168977 3 3
+19 161548 1 6
+19 161548 2 6
+19 161548 3 6
+19 497098 1 6
+19 497098 2 6
+19 497098 3 6
+19 51980 1 4
+19 51980 2 4
+19 51980 3 4
+19 84417 1 7
+19 84417 2 7
+19 84417 3 7
+19 508848 1 7
+19 508848 2 7
+19 508848 3 7
+19 249975 1 5
+19 249975 2 5
+19 249975 3 5
+19 471817 1 0
+19 471817 2 0
+19 471817 3 0
+19 420898 1 0
+19 420898 2 0
+19 420898 3 0
+19 62009 1 6
+19 62009 2 6
+19 62009 3 6
+19 261112 1 3
+19 261112 2 3
+19 261112 3 3
+19 268374 1 5
+19 268374 2 5
+19 268374 3 5
+19 92078 1 2
+19 92078 2 2
+19 92078 3 2
+19 146323 1 4
+19 146323 2 4
+19 146323 3 4
+19 48955 1 5
+19 48955 2 5
+19 48955 3 5
+19 336033 1 0
+19 336033 2 0
+19 336033 3 0
+19 4833 1 6
+19 4833 2 6
+19 4833 3 6
+19 359506 1 1
+19 359506 2 1
+19 359506 3 1
+19 477037 1 7
+19 477037 2 7
+19 477037 3 7
+19 109440 1 0
+19 109440 2 0
+19 109440 3 0
+19 27324 1 4
+19 27324 2 4
+19 27324 3 4
+19 361772 1 0
+19 361772 2 0
+19 361772 3 0
+19 150657 1 1
+19 150657 2 1
+19 150657 3 1
+19 174825 1 6
+19 174825 2 6
+19 174825 3 6
+19 352070 1 5
+19 352070 2 5
+19 352070 3 5
+19 195450 1 3
+19 195450 2 3
+19 195450 3 3
+19 468400 1 2
+19 468400 2 2
+19 468400 3 2
+19 330682 1 6
+19 330682 2 6
+19 330682 3 6
+19 45062 1 5
+19 45062 2 5
+19 45062 3 5
+19 313788 1 1
+19 313788 2 1
+19 313788 3 1
+19 60915 1 6
+19 60915 2 6
+19 60915 3 6
+19 44594 1 5
+19 44594 2 5
+19 44594 3 5
+19 252043 1 7
+19 252043 2 7
+19 252043 3 7
+19 401426 1 3
+19 401426 2 3
+19 401426 3 3
+19 243851 1 7
+19 243851 2 7
+19 243851 3 7
+19 388726 1 6
+19 388726 2 6
+19 388726 3 6
+19 134372 1 1
+19 134372 2 1
+19 134372 3 1
+19 263363 1 5
+19 263363 2 5
+19 263363 3 5
+19 120186 1 1
+19 120186 2 1
+19 120186 3 1
+19 245005 1 3
+19 245005 2 3
+19 245005 3 3
+19 345640 1 8
+19 345640 2 8
+19 345640 3 8
+19 292026 1 8
+19 292026 2 8
+19 292026 3 8
+19 337415 1 6
+19 337415 2 6
+19 337415 3 6
+19 18276 1 2
+19 18276 2 2
+19 18276 3 2
+19 24304 1 7
+19 24304 2 7
+19 24304 3 7
+19 70660 1 1
+19 70660 2 1
+19 70660 3 1
+19 426302 1 3
+19 426302 2 3
+19 426302 3 3
+19 405580 1 1
+19 405580 2 1
+19 405580 3 1
+19 16344 1 4
+19 16344 2 4
+19 16344 3 4
+19 486995 1 3
+19 486995 2 3
+19 486995 3 3
+19 338030 1 7
+19 338030 2 7
+19 338030 3 7
+19 22647 1 4
+19 22647 2 4
+19 22647 3 4
+19 400385 1 4
+19 400385 2 4
+19 400385 3 4
+19 51070 1 4
+19 51070 2 4
+19 51070 3 4
+19 19369 1 6
+19 19369 2 6
+19 19369 3 6
+19 407294 1 7
+19 407294 2 7
+19 407294 3 7
+19 310674 1 8
+19 310674 2 8
+19 310674 3 8
+19 228351 1 6
+19 228351 2 6
+19 228351 3 6
+19 302663 1 8
+19 302663 2 8
+19 302663 3 8
+20 198355 1 1
+20 198355 2 1
+20 198355 3 1
+20 296878 1 7
+20 296878 2 7
+20 296878 3 7
+20 760518 1 1
+20 760518 2 1
+20 760518 3 1
+20 924592 1 7
+20 924592 2 7
+20 924592 3 7
+20 561909 1 7
+20 561909 2 7
+20 561909 3 7
+20 364293 1 6
+20 364293 2 6
+20 364293 3 6
+20 431304 1 2
+20 431304 2 2
+20 431304 3 2
+20 24977 1 2
+20 24977 2 2
+20 24977 3 2
+20 98684 1 8
+20 98684 2 8
+20 98684 3 8
+20 116875 1 5
+20 116875 2 5
+20 116875 3 5
+20 121330 1 2
+20 121330 2 2
+20 121330 3 2
+20 977011 1 5
+20 977011 2 5
+20 977011 3 5
+20 789443 1 2
+20 789443 2 2
+20 789443 3 2
+20 539203 1 3
+20 539203 2 3
+20 539203 3 3
+20 981911 1 7
+20 981911 2 7
+20 981911 3 7
+20 495588 1 7
+20 495588 2 7
+20 495588 3 7
+20 24759 1 8
+20 24759 2 8
+20 24759 3 8
+20 355299 1 5
+20 355299 2 5
+20 355299 3 5
+20 706015 1 7
+20 706015 2 7
+20 706015 3 7
+20 1024100 1 7
+20 1024100 2 7
+20 1024100 3 7
+20 672600 1 7
+20 672600 2 7
+20 672600 3 7
+20 420182 1 1
+20 420182 2 1
+20 420182 3 1
+20 149062 1 1
+20 149062 2 1
+20 149062 3 1
+20 292328 1 3
+20 292328 2 3
+20 292328 3 3
+20 522558 1 2
+20 522558 2 2
+20 522558 3 2
+20 628026 1 1
+20 628026 2 1
+20 628026 3 1
+20 139803 1 8
+20 139803 2 8
+20 139803 3 8
+20 457303 1 1
+20 457303 2 1
+20 457303 3 1
+20 559378 1 7
+20 559378 2 7
+20 559378 3 7
+20 478051 1 6
+20 478051 2 6
+20 478051 3 6
+20 670978 1 5
+20 670978 2 5
+20 670978 3 5
+20 782352 1 1
+20 782352 2 1
+20 782352 3 1
+20 215312 1 0
+20 215312 2 0
+20 215312 3 0
+20 807766 1 4
+20 807766 2 4
+20 807766 3 4
+20 1027955 1 6
+20 1027955 2 6
+20 1027955 3 6
+20 724067 1 1
+20 724067 2 1
+20 724067 3 1
+20 179596 1 6
+20 179596 2 6
+20 179596 3 6
+20 8911 1 6
+20 8911 2 6
+20 8911 3 6
+20 462137 1 6
+20 462137 2 6
+20 462137 3 6
+20 451091 1 8
+20 451091 2 8
+20 451091 3 8
+20 837481 1 4
+20 837481 2 4
+20 837481 3 4
+20 61499 1 7
+20 61499 2 7
+20 61499 3 7
+20 64499 1 6
+20 64499 2 6
+20 64499 3 6
+20 498651 1 2
+20 498651 2 2
+20 498651 3 2
+20 139939 1 6
+20 139939 2 6
+20 139939 3 6
+20 1021247 1 6
+20 1021247 2 6
+20 1021247 3 6
+20 203158 1 4
+20 203158 2 4
+20 203158 3 4
+20 165605 1 5
+20 165605 2 5
+20 165605 3 5
+20 996551 1 6
+20 996551 2 6
+20 996551 3 6
+20 344367 1 1
+20 344367 2 1
+20 344367 3 1
+20 471785 1 7
+20 471785 2 7
+20 471785 3 7
+20 552276 1 8
+20 552276 2 8
+20 552276 3 8
+20 535414 1 4
+20 535414 2 4
+20 535414 3 4
+20 850839 1 6
+20 850839 2 6
+20 850839 3 6
+20 707079 1 2
+20 707079 2 2
+20 707079 3 2
+20 311484 1 2
+20 311484 2 2
+20 311484 3 2
+20 682726 1 6
+20 682726 2 6
+20 682726 3 6
+20 718518 1 4
+20 718518 2 4
+20 718518 3 4
+20 584929 1 6
+20 584929 2 6
+20 584929 3 6
+20 496804 1 4
+20 496804 2 4
+20 496804 3 4
+20 871520 1 7
+20 871520 2 7
+20 871520 3 7
+20 766462 1 6
+20 766462 2 6
+20 766462 3 6
+20 547770 1 5
+20 547770 2 5
+20 547770 3 5
+20 289035 1 8
+20 289035 2 8
+20 289035 3 8
+21 1544102 1 3
+21 1544102 2 3
+21 1544102 3 3
+21 1921124 1 8
+21 1921124 2 8
+21 1921124 3 8
+21 1244065 1 6
+21 1244065 2 6
+21 1244065 3 6
+21 949419 1 7
+21 949419 2 7
+21 949419 3 7
+21 809660 1 5
+21 809660 2 5
+21 809660 3 5
+21 2081078 1 4
+21 2081078 2 4
+21 2081078 3 4
+21 1324116 1 0
+21 1324116 2 0
+21 1324116 3 0
+21 769413 1 0
+21 769413 2 0
+21 769413 3 0
+21 1471174 1 1
+21 1471174 2 1
+21 1471174 3 1
+21 2010804 1 6
+21 2010804 2 6
+21 2010804 3 6
+21 1616690 1 1
+21 1616690 2 1
+21 1616690 3 1
+21 1017561 1 7
+21 1017561 2 7
+21 1017561 3 7
+21 957826 1 7
+21 957826 2 7
+21 957826 3 7
+21 562864 1 4
+21 562864 2 4
+21 562864 3 4
+21 536746 1 8
+21 536746 2 8
+21 536746 3 8
+21 2010490 1 3
+21 2010490 2 3
+21 2010490 3 3
+21 814896 1 3
+21 814896 2 3
+21 814896 3 3
+21 2085665 1 5
+21 2085665 2 5
+21 2085665 3 5
+21 608239 1 4
+21 608239 2 4
+21 608239 3 4
+21 1114271 1 6
+21 1114271 2 6
+21 1114271 3 6
+21 1578775 1 5
+21 1578775 2 5
+21 1578775 3 5
+21 293537 1 7
+21 293537 2 7
+21 293537 3 7
+21 1260407 1 8
+21 1260407 2 8
+21 1260407 3 8
+21 569959 1 4
+21 569959 2 4
+21 569959 3 4
+21 1653758 1 5
+21 1653758 2 5
+21 1653758 3 5
+21 643309 1 0
+21 643309 2 0
+21 643309 3 0
+21 1982846 1 1
+21 1982846 2 1
+21 1982846 3 1
+21 1986639 1 8
+21 1986639 2 8
+21 1986639 3 8
+21 1370291 1 4
+21 1370291 2 4
+21 1370291 3 4
+21 1656681 1 6
+21 1656681 2 6
+21 1656681 3 6
+21 241796 1 3
+21 241796 2 3
+21 241796 3 3
+21 215997 1 8
+21 215997 2 8
+21 215997 3 8
+21 821384 1 3
+21 821384 2 3
+21 821384 3 3
+21 331161 1 6
+21 331161 2 6
+21 331161 3 6
+21 17355 1 8
+21 17355 2 8
+21 17355 3 8
+21 1905273 1 8
+21 1905273 2 8
+21 1905273 3 8
+21 1045457 1 7
+21 1045457 2 7
+21 1045457 3 7
+21 799145 1 0
+21 799145 2 0
+21 799145 3 0
+21 683994 1 7
+21 683994 2 7
+21 683994 3 7
+21 1750830 1 8
+21 1750830 2 8
+21 1750830 3 8
+21 1346663 1 5
+21 1346663 2 5
+21 1346663 3 5
+21 1200358 1 7
+21 1200358 2 7
+21 1200358 3 7
+21 968444 1 4
+21 968444 2 4
+21 968444 3 4
+21 469486 1 6
+21 469486 2 6
+21 469486 3 6
+21 223784 1 0
+21 223784 2 0
+21 223784 3 0
+21 841795 1 4
+21 841795 2 4
+21 841795 3 4
+21 290242 1 2
+21 290242 2 2
+21 290242 3 2
+21 1704107 1 2
+21 1704107 2 2
+21 1704107 3 2
+21 1087348 1 6
+21 1087348 2 6
+21 1087348 3 6
+21 513237 1 2
+21 513237 2 2
+21 513237 3 2
+21 761725 1 8
+21 761725 2 8
+21 761725 3 8
+21 577471 1 4
+21 577471 2 4
+21 577471 3 4
+21 875954 1 6
+21 875954 2 6
+21 875954 3 6
+21 283735 1 0
+21 283735 2 0
+21 283735 3 0
+21 541381 1 3
+21 541381 2 3
+21 541381 3 3
+21 1774181 1 6
+21 1774181 2 6
+21 1774181 3 6
+21 500169 1 3
+21 500169 2 3
+21 500169 3 3
+21 1201575 1 6
+21 1201575 2 6
+21 1201575 3 6
+21 691701 1 1
+21 691701 2 1
+21 691701 3 1
+21 172861 1 4
+21 172861 2 4
+21 172861 3 4
+21 544935 1 3
+21 544935 2 3
+21 544935 3 3
+21 543047 1 0
+21 543047 2 0
+21 543047 3 0
+21 1555372 1 6
+21 1555372 2 6
+21 1555372 3 6
+21 1754316 1 8
+21 1754316 2 8
+21 1754316 3 8
+22 1701163 1 7
+22 1701163 2 7
+22 1701163 3 7
+22 2291265 1 8
+22 2291265 2 8
+22 2291265 3 8
+22 2939154 1 3
+22 2939154 2 3
+22 2939154 3 3
+22 874939 1 8
+22 874939 2 8
+22 874939 3 8
+22 66406 1 0
+22 66406 2 0
+22 66406 3 0
+22 2173604 1 3
+22 2173604 2 3
+22 2173604 3 3
+22 3888560 1 7
+22 3888560 2 7
+22 3888560 3 7
+22 633256 1 7
+22 633256 2 7
+22 633256 3 7
+22 499433 1 6
+22 499433 2 6
+22 499433 3 6
+22 523322 1 6
+22 523322 2 6
+22 523322 3 6
+22 3422065 1 6
+22 3422065 2 6
+22 3422065 3 6
+22 1944488 1 3
+22 1944488 2 3
+22 1944488 3 3
+22 1501254 1 5
+22 1501254 2 5
+22 1501254 3 5
+22 3637609 1 2
+22 3637609 2 2
+22 3637609 3 2
+22 3969393 1 6
+22 3969393 2 6
+22 3969393 3 6
+22 3757241 1 1
+22 3757241 2 1
+22 3757241 3 1
+22 541635 1 2
+22 541635 2 2
+22 541635 3 2
+22 40295 1 7
+22 40295 2 7
+22 40295 3 7
+22 4047297 1 8
+22 4047297 2 8
+22 4047297 3 8
+22 3989485 1 8
+22 3989485 2 8
+22 3989485 3 8
+22 4103132 1 8
+22 4103132 2 8
+22 4103132 3 8
+22 1722049 1 7
+22 1722049 2 7
+22 1722049 3 7
+22 23525 1 2
+22 23525 2 2
+22 23525 3 2
+22 2882794 1 5
+22 2882794 2 5
+22 2882794 3 5
+22 3503039 1 1
+22 3503039 2 1
+22 3503039 3 1
+22 597461 1 7
+22 597461 2 7
+22 597461 3 7
+22 648021 1 7
+22 648021 2 7
+22 648021 3 7
+22 2641512 1 7
+22 2641512 2 7
+22 2641512 3 7
+22 3131854 1 6
+22 3131854 2 6
+22 3131854 3 6
+22 3363671 1 7
+22 3363671 2 7
+22 3363671 3 7
+22 480767 1 0
+22 480767 2 0
+22 480767 3 0
+22 866487 1 2
+22 866487 2 2
+22 866487 3 2
+22 3197473 1 8
+22 3197473 2 8
+22 3197473 3 8
+22 1760976 1 6
+22 1760976 2 6
+22 1760976 3 6
+22 952003 1 4
+22 952003 2 4
+22 952003 3 4
+22 458806 1 4
+22 458806 2 4
+22 458806 3 4
+22 2642177 1 2
+22 2642177 2 2
+22 2642177 3 2
+22 3671322 1 4
+22 3671322 2 4
+22 3671322 3 4
+22 18422 1 3
+22 18422 2 3
+22 18422 3 3
+22 4143069 1 8
+22 4143069 2 8
+22 4143069 3 8
+22 4013422 1 3
+22 4013422 2 3
+22 4013422 3 3
+22 3026661 1 5
+22 3026661 2 5
+22 3026661 3 5
+22 1402336 1 5
+22 1402336 2 5
+22 1402336 3 5
+22 3702708 1 6
+22 3702708 2 6
+22 3702708 3 6
+22 2069402 1 8
+22 2069402 2 8
+22 2069402 3 8
+22 1380150 1 6
+22 1380150 2 6
+22 1380150 3 6
+22 2126142 1 8
+22 2126142 2 8
+22 2126142 3 8
+22 3380057 1 8
+22 3380057 2 8
+22 3380057 3 8
+22 814956 1 6
+22 814956 2 6
+22 814956 3 6
+22 1055203 1 6
+22 1055203 2 6
+22 1055203 3 6
+22 940480 1 8
+22 940480 2 8
+22 940480 3 8
+22 3647615 1 5
+22 3647615 2 5
+22 3647615 3 5
+22 3000063 1 5
+22 3000063 2 5
+22 3000063 3 5
+22 3033624 1 8
+22 3033624 2 8
+22 3033624 3 8
+22 3135628 1 7
+22 3135628 2 7
+22 3135628 3 7
+22 1580393 1 1
+22 1580393 2 1
+22 1580393 3 1
+22 4193568 1 2
+22 4193568 2 2
+22 4193568 3 2
+22 800980 1 4
+22 800980 2 4
+22 800980 3 4
+22 1419961 1 5
+22 1419961 2 5
+22 1419961 3 5
+22 1144691 1 7
+22 1144691 2 7
+22 1144691 3 7
+22 2573267 1 2
+22 2573267 2 2
+22 2573267 3 2
+22 3310445 1 4
+22 3310445 2 4
+22 3310445 3 4
+22 629717 1 3
+22 629717 2 3
+22 629717 3 3
+22 1552778 1 7
+22 1552778 2 7
+22 1552778 3 7
+23 3046911 1 1
+23 3046911 2 1
+23 3046911 3 1
+23 769783 1 1
+23 769783 2 1
+23 769783 3 1
+23 2374124 1 4
+23 2374124 2 4
+23 2374124 3 4
+23 2996918 1 7
+23 2996918 2 7
+23 2996918 3 7
+23 2411310 1 6
+23 2411310 2 6
+23 2411310 3 6
+23 744660 1 0
+23 744660 2 0
+23 744660 3 0
+23 7927100 1 8
+23 7927100 2 8
+23 7927100 3 8
+23 1377692 1 0
+23 1377692 2 0
+23 1377692 3 0
+23 2920499 1 4
+23 2920499 2 4
+23 2920499 3 4
+23 6611555 1 4
+23 6611555 2 4
+23 6611555 3 4
+23 723122 1 8
+23 723122 2 8
+23 723122 3 8
+23 5130765 1 7
+23 5130765 2 7
+23 5130765 3 7
+23 621060 1 5
+23 621060 2 5
+23 621060 3 5
+23 6806998 1 1
+23 6806998 2 1
+23 6806998 3 1
+23 3524228 1 7
+23 3524228 2 7
+23 3524228 3 7
+23 1077839 1 8
+23 1077839 2 8
+23 1077839 3 8
+23 5526077 1 4
+23 5526077 2 4
+23 5526077 3 4
+23 7013541 1 8
+23 7013541 2 8
+23 7013541 3 8
+23 4998096 1 4
+23 4998096 2 4
+23 4998096 3 4
+23 5128233 1 8
+23 5128233 2 8
+23 5128233 3 8
+23 1863578 1 7
+23 1863578 2 7
+23 1863578 3 7
+23 6838283 1 7
+23 6838283 2 7
+23 6838283 3 7
+23 1134869 1 1
+23 1134869 2 1
+23 1134869 3 1
+23 2111849 1 4
+23 2111849 2 4
+23 2111849 3 4
+23 1488511 1 1
+23 1488511 2 1
+23 1488511 3 1
+23 4807048 1 6
+23 4807048 2 6
+23 4807048 3 6
+23 393912 1 6
+23 393912 2 6
+23 393912 3 6
+23 5219424 1 0
+23 5219424 2 0
+23 5219424 3 0
+23 8137072 1 7
+23 8137072 2 7
+23 8137072 3 7
+23 5590877 1 8
+23 5590877 2 8
+23 5590877 3 8
+23 5294465 1 7
+23 5294465 2 7
+23 5294465 3 7
+23 1348707 1 7
+23 1348707 2 7
+23 1348707 3 7
+23 7997848 1 3
+23 7997848 2 3
+23 7997848 3 3
+23 7575827 1 3
+23 7575827 2 3
+23 7575827 3 3
+23 4135707 1 7
+23 4135707 2 7
+23 4135707 3 7
+23 5834316 1 0
+23 5834316 2 0
+23 5834316 3 0
+23 5605190 1 7
+23 5605190 2 7
+23 5605190 3 7
+23 3412980 1 7
+23 3412980 2 7
+23 3412980 3 7
+23 2337431 1 8
+23 2337431 2 8
+23 2337431 3 8
+23 1248504 1 4
+23 1248504 2 4
+23 1248504 3 4
+23 2425452 1 1
+23 2425452 2 1
+23 2425452 3 1
+23 5214096 1 5
+23 5214096 2 5
+23 5214096 3 5
+23 1257705 1 0
+23 1257705 2 0
+23 1257705 3 0
+23 527815 1 4
+23 527815 2 4
+23 527815 3 4
+23 4250399 1 5
+23 4250399 2 5
+23 4250399 3 5
+23 1200698 1 6
+23 1200698 2 6
+23 1200698 3 6
+23 4310378 1 1
+23 4310378 2 1
+23 4310378 3 1
+23 724255 1 6
+23 724255 2 6
+23 724255 3 6
+23 5100058 1 0
+23 5100058 2 0
+23 5100058 3 0
+23 6466953 1 4
+23 6466953 2 4
+23 6466953 3 4
+23 181844 1 3
+23 181844 2 3
+23 181844 3 3
+23 527081 1 1
+23 527081 2 1
+23 527081 3 1
+23 194874 1 6
+23 194874 2 6
+23 194874 3 6
+23 5612248 1 7
+23 5612248 2 7
+23 5612248 3 7
+23 2969929 1 4
+23 2969929 2 4
+23 2969929 3 4
+23 7237394 1 7
+23 7237394 2 7
+23 7237394 3 7
+23 865283 1 7
+23 865283 2 7
+23 865283 3 7
+23 235461 1 2
+23 235461 2 2
+23 235461 3 2
+23 6769613 1 0
+23 6769613 2 0
+23 6769613 3 0
+23 5015052 1 7
+23 5015052 2 7
+23 5015052 3 7
+23 3295257 1 8
+23 3295257 2 8
+23 3295257 3 8
+23 989877 1 7
+23 989877 2 7
+23 989877 3 7
+23 1637319 1 6
+23 1637319 2 6
+23 1637319 3 6
+23 3018058 1 7
+23 3018058 2 7
+23 3018058 3 7
+24 9775649 1 4
+24 9775649 2 4
+24 9775649 3 4
+24 14133895 1 1
+24 14133895 2 1
+24 14133895 3 1
+24 3743280 1 8
+24 3743280 2 8
+24 3743280 3 8
+24 1023898 1 7
+24 1023898 2 7
+24 1023898 3 7
+24 9941521 1 1
+24 9941521 2 1
+24 9941521 3 1
+24 10377160 1 1
+24 10377160 2 1
+24 10377160 3 1
+24 11342584 1 7
+24 11342584 2 7
+24 11342584 3 7
+24 9294179 1 1
+24 9294179 2 1
+24 9294179 3 1
+24 15025827 1 7
+24 15025827 2 7
+24 15025827 3 7
+24 3498285 1 7
+24 3498285 2 7
+24 3498285 3 7
+24 8199923 1 5
+24 8199923 2 5
+24 8199923 3 5
+24 90634 1 6
+24 90634 2 6
+24 90634 3 6
+24 12997310 1 5
+24 12997310 2 5
+24 12997310 3 5
+24 14265335 1 6
+24 14265335 2 6
+24 14265335 3 6
+24 5492707 1 4
+24 5492707 2 4
+24 5492707 3 4
+24 263738 1 3
+24 263738 2 3
+24 263738 3 3
+24 13671070 1 3
+24 13671070 2 3
+24 13671070 3 3
+24 8325339 1 6
+24 8325339 2 6
+24 8325339 3 6
+24 9752092 1 6
+24 9752092 2 6
+24 9752092 3 6
+24 10821970 1 8
+24 10821970 2 8
+24 10821970 3 8
+24 3248722 1 0
+24 3248722 2 0
+24 3248722 3 0
+24 11447937 1 3
+24 11447937 2 3
+24 11447937 3 3
+24 6691593 1 6
+24 6691593 2 6
+24 6691593 3 6
+24 10840036 1 7
+24 10840036 2 7
+24 10840036 3 7
+24 8193085 1 6
+24 8193085 2 6
+24 8193085 3 6
+24 13272070 1 3
+24 13272070 2 3
+24 13272070 3 3
+24 3317672 1 5
+24 3317672 2 5
+24 3317672 3 5
+24 9720374 1 4
+24 9720374 2 4
+24 9720374 3 4
+24 3803032 1 0
+24 3803032 2 0
+24 3803032 3 0
+24 8338298 1 5
+24 8338298 2 5
+24 8338298 3 5
+24 8391433 1 0
+24 8391433 2 0
+24 8391433 3 0
+24 3759812 1 3
+24 3759812 2 3
+24 3759812 3 3
+24 11028207 1 3
+24 11028207 2 3
+24 11028207 3 3
+24 7289955 1 0
+24 7289955 2 0
+24 7289955 3 0
+24 3277010 1 3
+24 3277010 2 3
+24 3277010 3 3
+24 15934652 1 4
+24 15934652 2 4
+24 15934652 3 4
+24 7837344 1 7
+24 7837344 2 7
+24 7837344 3 7
+24 6315577 1 4
+24 6315577 2 4
+24 6315577 3 4
+24 9738174 1 3
+24 9738174 2 3
+24 9738174 3 3
+24 16135808 1 4
+24 16135808 2 4
+24 16135808 3 4
+24 7068511 1 4
+24 7068511 2 4
+24 7068511 3 4
+24 7762664 1 5
+24 7762664 2 5
+24 7762664 3 5
+24 13117465 1 6
+24 13117465 2 6
+24 13117465 3 6
+24 9819176 1 0
+24 9819176 2 0
+24 9819176 3 0
+24 2572469 1 1
+24 2572469 2 1
+24 2572469 3 1
+24 4497745 1 8
+24 4497745 2 8
+24 4497745 3 8
+24 6842950 1 6
+24 6842950 2 6
+24 6842950 3 6
+24 28157 1 7
+24 28157 2 7
+24 28157 3 7
+24 9748348 1 6
+24 9748348 2 6
+24 9748348 3 6
+24 12554184 1 2
+24 12554184 2 2
+24 12554184 3 2
+24 8971577 1 6
+24 8971577 2 6
+24 8971577 3 6
+24 1701631 1 6
+24 1701631 2 6
+24 1701631 3 6
+24 11334757 1 6
+24 11334757 2 6
+24 11334757 3 6
+24 5922455 1 5
+24 5922455 2 5
+24 5922455 3 5
+24 6335742 1 8
+24 6335742 2 8
+24 6335742 3 8
+24 6162272 1 4
+24 6162272 2 4
+24 6162272 3 4
+24 9389682 1 7
+24 9389682 2 7
+24 9389682 3 7
+24 14185082 1 6
+24 14185082 2 6
+24 14185082 3 6
+24 4157744 1 1
+24 4157744 2 1
+24 4157744 3 1
+24 15978247 1 4
+24 15978247 2 4
+24 15978247 3 4
+24 2710908 1 7
+24 2710908 2 7
+24 2710908 3 7
+24 10358562 1 5
+24 10358562 2 5
+24 10358562 3 5
+24 10869634 1 1
+24 10869634 2 1
+24 10869634 3 1
+24 6150158 1 7
+24 6150158 2 7
+24 6150158 3 7
+25 27898613 1 5
+25 27898613 2 5
+25 27898613 3 5
+25 29501 1 1
+25 29501 2 1
+25 29501 3 1
+25 15761162 1 8
+25 15761162 2 8
+25 15761162 3 8
+25 15728788 1 8
+25 15728788 2 8
+25 15728788 3 8
+25 33257945 1 0
+25 33257945 2 0
+25 33257945 3 0
+25 25725432 1 7
+25 25725432 2 7
+25 25725432 3 7
+25 32158340 1 4
+25 32158340 2 4
+25 32158340 3 4
+25 14232919 1 3
+25 14232919 2 3
+25 14232919 3 3
+25 25835501 1 3
+25 25835501 2 3
+25 25835501 3 3
+25 17975125 1 6
+25 17975125 2 6
+25 17975125 3 6
+25 1306676 1 0
+25 1306676 2 0
+25 1306676 3 0
+25 15859824 1 4
+25 15859824 2 4
+25 15859824 3 4
+25 28894333 1 4
+25 28894333 2 4
+25 28894333 3 4
+25 9046116 1 8
+25 9046116 2 8
+25 9046116 3 8
+25 26019062 1 7
+25 26019062 2 7
+25 26019062 3 7
+25 1778640 1 1
+25 1778640 2 1
+25 1778640 3 1
+25 10266904 1 1
+25 10266904 2 1
+25 10266904 3 1
+25 6909977 1 1
+25 6909977 2 1
+25 6909977 3 1
+25 10702892 1 2
+25 10702892 2 2
+25 10702892 3 2
+25 11960717 1 3
+25 11960717 2 3
+25 11960717 3 3
+25 5203472 1 1
+25 5203472 2 1
+25 5203472 3 1
+25 29147083 1 5
+25 29147083 2 5
+25 29147083 3 5
+25 24580154 1 3
+25 24580154 2 3
+25 24580154 3 3
+25 14263395 1 8
+25 14263395 2 8
+25 14263395 3 8
+25 22955773 1 3
+25 22955773 2 3
+25 22955773 3 3
+25 21675961 1 8
+25 21675961 2 8
+25 21675961 3 8
+25 7257867 1 7
+25 7257867 2 7
+25 7257867 3 7
+25 20686894 1 5
+25 20686894 2 5
+25 20686894 3 5
+25 29779770 1 7
+25 29779770 2 7
+25 29779770 3 7
+25 27342720 1 6
+25 27342720 2 6
+25 27342720 3 6
+25 622218 1 0
+25 622218 2 0
+25 622218 3 0
+25 12630641 1 0
+25 12630641 2 0
+25 12630641 3 0
+25 3245670 1 0
+25 3245670 2 0
+25 3245670 3 0
+25 521894 1 2
+25 521894 2 2
+25 521894 3 2
+25 14849322 1 8
+25 14849322 2 8
+25 14849322 3 8
+25 12921554 1 0
+25 12921554 2 0
+25 12921554 3 0
+25 23383269 1 7
+25 23383269 2 7
+25 23383269 3 7
+25 10251539 1 4
+25 10251539 2 4
+25 10251539 3 4
+25 16251487 1 7
+25 16251487 2 7
+25 16251487 3 7
+25 9046939 1 0
+25 9046939 2 0
+25 9046939 3 0
+25 1286237 1 3
+25 1286237 2 3
+25 1286237 3 3
+25 1561491 1 6
+25 1561491 2 6
+25 1561491 3 6
+25 25555747 1 6
+25 25555747 2 6
+25 25555747 3 6
+25 6644283 1 7
+25 6644283 2 7
+25 6644283 3 7
+25 25724985 1 6
+25 25724985 2 6
+25 25724985 3 6
+25 123989 1 6
+25 123989 2 6
+25 123989 3 6
+25 17415794 1 8
+25 17415794 2 8
+25 17415794 3 8
+25 26732483 1 8
+25 26732483 2 8
+25 26732483 3 8
+25 30810665 1 8
+25 30810665 2 8
+25 30810665 3 8
+25 5383023 1 3
+25 5383023 2 3
+25 5383023 3 3
+25 20795854 1 1
+25 20795854 2 1
+25 20795854 3 1
+25 32135530 1 6
+25 32135530 2 6
+25 32135530 3 6
+25 8529568 1 0
+25 8529568 2 0
+25 8529568 3 0
+25 29472599 1 0
+25 29472599 2 0
+25 29472599 3 0
+25 18752955 1 7
+25 18752955 2 7
+25 18752955 3 7
+25 7624970 1 6
+25 7624970 2 6
+25 7624970 3 6
+25 14450005 1 4
+25 14450005 2 4
+25 14450005 3 4
+25 5230955 1 4
+25 5230955 2 4
+25 5230955 3 4
+25 22090308 1 5
+25 22090308 2 5
+25 22090308 3 5
+25 19848608 1 0
+25 19848608 2 0
+25 19848608 3 0
+25 24404419 1 6
+25 24404419 2 6
+25 24404419 3 6
+25 29009514 1 7
+25 29009514 2 7
+25 29009514 3 7
+25 24460148 1 6
+25 24460148 2 6
+25 24460148 3 6
+25 20198351 1 5
+25 20198351 2 5
+25 20198351 3 5
+26 7084154 1 7
+26 7084154 2 7
+26 7084154 3 7
+26 25565466 1 6
+26 25565466 2 6
+26 25565466 3 6
+26 46816379 1 2
+26 46816379 2 2
+26 46816379 3 2
+26 21945765 1 7
+26 21945765 2 7
+26 21945765 3 7
+26 13640323 1 3
+26 13640323 2 3
+26 13640323 3 3
+26 30012262 1 5
+26 30012262 2 5
+26 30012262 3 5
+26 20042720 1 3
+26 20042720 2 3
+26 20042720 3 3
+26 16193914 1 7
+26 16193914 2 7
+26 16193914 3 7
+26 10183696 1 4
+26 10183696 2 4
+26 10183696 3 4
+26 24876252 1 0
+26 24876252 2 0
+26 24876252 3 0
+26 5209203 1 8
+26 5209203 2 8
+26 5209203 3 8
+26 18883903 1 8
+26 18883903 2 8
+26 18883903 3 8
+26 48312129 1 8
+26 48312129 2 8
+26 48312129 3 8
+26 24703773 1 5
+26 24703773 2 5
+26 24703773 3 5
+26 65103293 1 6
+26 65103293 2 6
+26 65103293 3 6
+26 64342799 1 8
+26 64342799 2 8
+26 64342799 3 8
+26 54033834 1 8
+26 54033834 2 8
+26 54033834 3 8
+26 11156063 1 8
+26 11156063 2 8
+26 11156063 3 8
+26 58182142 1 7
+26 58182142 2 7
+26 58182142 3 7
+26 25321691 1 3
+26 25321691 2 3
+26 25321691 3 3
+26 49670869 1 6
+26 49670869 2 6
+26 49670869 3 6
+26 9604075 1 8
+26 9604075 2 8
+26 9604075 3 8
+26 21246120 1 7
+26 21246120 2 7
+26 21246120 3 7
+26 54324966 1 8
+26 54324966 2 8
+26 54324966 3 8
+26 12222142 1 8
+26 12222142 2 8
+26 12222142 3 8
+26 46795936 1 3
+26 46795936 2 3
+26 46795936 3 3
+26 28991713 1 4
+26 28991713 2 4
+26 28991713 3 4
+26 21341767 1 3
+26 21341767 2 3
+26 21341767 3 3
+26 35735637 1 7
+26 35735637 2 7
+26 35735637 3 7
+26 20661103 1 7
+26 20661103 2 7
+26 20661103 3 7
+26 40707078 1 7
+26 40707078 2 7
+26 40707078 3 7
+26 53127018 1 3
+26 53127018 2 3
+26 53127018 3 3
+26 43370495 1 8
+26 43370495 2 8
+26 43370495 3 8
+26 4048861 1 3
+26 4048861 2 3
+26 4048861 3 3
+26 30464035 1 2
+26 30464035 2 2
+26 30464035 3 2
+26 5183631 1 1
+26 5183631 2 1
+26 5183631 3 1
+26 27077142 1 7
+26 27077142 2 7
+26 27077142 3 7
+26 48775300 1 5
+26 48775300 2 5
+26 48775300 3 5
+26 13488763 1 7
+26 13488763 2 7
+26 13488763 3 7
+26 13536330 1 0
+26 13536330 2 0
+26 13536330 3 0
+26 35410276 1 5
+26 35410276 2 5
+26 35410276 3 5
+26 53719442 1 5
+26 53719442 2 5
+26 53719442 3 5
+26 38572550 1 7
+26 38572550 2 7
+26 38572550 3 7
+26 66500609 1 4
+26 66500609 2 4
+26 66500609 3 4
+26 56930732 1 5
+26 56930732 2 5
+26 56930732 3 5
+26 13245256 1 3
+26 13245256 2 3
+26 13245256 3 3
+26 2474478 1 6
+26 2474478 2 6
+26 2474478 3 6
+26 47282801 1 6
+26 47282801 2 6
+26 47282801 3 6
+26 1178146 1 8
+26 1178146 2 8
+26 1178146 3 8
+26 43673724 1 6
+26 43673724 2 6
+26 43673724 3 6
+26 2100241 1 6
+26 2100241 2 6
+26 2100241 3 6
+26 41497130 1 7
+26 41497130 2 7
+26 41497130 3 7
+26 33722349 1 7
+26 33722349 2 7
+26 33722349 3 7
+26 9153815 1 6
+26 9153815 2 6
+26 9153815 3 6
+26 48610178 1 4
+26 48610178 2 4
+26 48610178 3 4
+26 53568526 1 2
+26 53568526 2 2
+26 53568526 3 2
+26 32823468 1 2
+26 32823468 2 2
+26 32823468 3 2
+26 65647768 1 8
+26 65647768 2 8
+26 65647768 3 8
+26 35401480 1 6
+26 35401480 2 6
+26 35401480 3 6
+26 41791958 1 8
+26 41791958 2 8
+26 41791958 3 8
+26 9655534 1 8
+26 9655534 2 8
+26 9655534 3 8
+26 40165520 1 8
+26 40165520 2 8
+26 40165520 3 8
+26 34020254 1 4
+26 34020254 2 4
+26 34020254 3 4
+26 61939853 1 8
+26 61939853 2 8
+26 61939853 3 8
+27 92315981 1 7
+27 92315981 2 7
+27 92315981 3 7
+27 61792721 1 6
+27 61792721 2 6
+27 61792721 3 6
+27 92388693 1 1
+27 92388693 2 1
+27 92388693 3 1
+27 53427871 1 7
+27 53427871 2 7
+27 53427871 3 7
+27 120842826 1 1
+27 120842826 2 1
+27 120842826 3 1
+27 28583319 1 7
+27 28583319 2 7
+27 28583319 3 7
+27 124744556 1 5
+27 124744556 2 5
+27 124744556 3 5
+27 4355438 1 7
+27 4355438 2 7
+27 4355438 3 7
+27 4216154 1 6
+27 4216154 2 6
+27 4216154 3 6
+27 123239172 1 4
+27 123239172 2 4
+27 123239172 3 4
+27 115756467 1 7
+27 115756467 2 7
+27 115756467 3 7
+27 51430308 1 8
+27 51430308 2 8
+27 51430308 3 8
+27 64209151 1 5
+27 64209151 2 5
+27 64209151 3 5
+27 86593418 1 6
+27 86593418 2 6
+27 86593418 3 6
+27 18520784 1 7
+27 18520784 2 7
+27 18520784 3 7
+27 99412133 1 2
+27 99412133 2 2
+27 99412133 3 2
+27 17075236 1 3
+27 17075236 2 3
+27 17075236 3 3
+27 9740701 1 4
+27 9740701 2 4
+27 9740701 3 4
+27 42355725 1 7
+27 42355725 2 7
+27 42355725 3 7
+27 76792086 1 6
+27 76792086 2 6
+27 76792086 3 6
+27 34848403 1 7
+27 34848403 2 7
+27 34848403 3 7
+27 60857654 1 8
+27 60857654 2 8
+27 60857654 3 8
+27 89466329 1 1
+27 89466329 2 1
+27 89466329 3 1
+27 7416677 1 0
+27 7416677 2 0
+27 7416677 3 0
+27 94093693 1 8
+27 94093693 2 8
+27 94093693 3 8
+27 71977043 1 0
+27 71977043 2 0
+27 71977043 3 0
+27 32931909 1 6
+27 32931909 2 6
+27 32931909 3 6
+27 99417150 1 7
+27 99417150 2 7
+27 99417150 3 7
+27 78489591 1 5
+27 78489591 2 5
+27 78489591 3 5
+27 56442740 1 3
+27 56442740 2 3
+27 56442740 3 3
+27 49715079 1 2
+27 49715079 2 2
+27 49715079 3 2
+27 95552279 1 5
+27 95552279 2 5
+27 95552279 3 5
+27 119474039 1 8
+27 119474039 2 8
+27 119474039 3 8
+27 47612448 1 6
+27 47612448 2 6
+27 47612448 3 6
+27 125922426 1 1
+27 125922426 2 1
+27 125922426 3 1
+27 18947749 1 0
+27 18947749 2 0
+27 18947749 3 0
+27 92954715 1 7
+27 92954715 2 7
+27 92954715 3 7
+27 69488478 1 7
+27 69488478 2 7
+27 69488478 3 7
+27 36779293 1 8
+27 36779293 2 8
+27 36779293 3 8
+27 90333541 1 6
+27 90333541 2 6
+27 90333541 3 6
+27 113514082 1 1
+27 113514082 2 1
+27 113514082 3 1
+27 114627133 1 2
+27 114627133 2 2
+27 114627133 3 2
+27 67788048 1 4
+27 67788048 2 4
+27 67788048 3 4
+27 80102932 1 3
+27 80102932 2 3
+27 80102932 3 3
+27 80083249 1 8
+27 80083249 2 8
+27 80083249 3 8
+27 8871500 1 0
+27 8871500 2 0
+27 8871500 3 0
+27 96933402 1 6
+27 96933402 2 6
+27 96933402 3 6
+27 40432695 1 3
+27 40432695 2 3
+27 40432695 3 3
+27 55794895 1 8
+27 55794895 2 8
+27 55794895 3 8
+27 120388642 1 3
+27 120388642 2 3
+27 120388642 3 3
+27 64256165 1 0
+27 64256165 2 0
+27 64256165 3 0
+27 4822164 1 7
+27 4822164 2 7
+27 4822164 3 7
+27 14139945 1 3
+27 14139945 2 3
+27 14139945 3 3
+27 116590039 1 0
+27 116590039 2 0
+27 116590039 3 0
+27 61027392 1 4
+27 61027392 2 4
+27 61027392 3 4
+27 71808439 1 4
+27 71808439 2 4
+27 71808439 3 4
+27 4329359 1 8
+27 4329359 2 8
+27 4329359 3 8
+27 90248073 1 8
+27 90248073 2 8
+27 90248073 3 8
+27 53334044 1 7
+27 53334044 2 7
+27 53334044 3 7
+27 79216751 1 3
+27 79216751 2 3
+27 79216751 3 3
+27 14571829 1 7
+27 14571829 2 7
+27 14571829 3 7
+27 58816473 1 7
+27 58816473 2 7
+27 58816473 3 7
+27 97942416 1 8
+27 97942416 2 8
+27 97942416 3 8
+27 25656398 1 2
+27 25656398 2 2
+27 25656398 3 2
+28 115821936 1 6
+28 115821936 2 6
+28 115821936 3 6
+28 108711265 1 6
+28 108711265 2 6
+28 108711265 3 6
+28 51814809 1 8
+28 51814809 2 8
+28 51814809 3 8
+28 9511812 1 7
+28 9511812 2 7
+28 9511812 3 7
+28 119984430 1 0
+28 119984430 2 0
+28 119984430 3 0
+28 222765195 1 7
+28 222765195 2 7
+28 222765195 3 7
+28 44273960 1 3
+28 44273960 2 3
+28 44273960 3 3
+28 146489653 1 0
+28 146489653 2 0
+28 146489653 3 0
+28 242813898 1 7
+28 242813898 2 7
+28 242813898 3 7
+28 145291726 1 5
+28 145291726 2 5
+28 145291726 3 5
+28 64513013 1 1
+28 64513013 2 1
+28 64513013 3 1
+28 214162337 1 6
+28 214162337 2 6
+28 214162337 3 6
+28 210803129 1 2
+28 210803129 2 2
+28 210803129 3 2
+28 60497323 1 8
+28 60497323 2 8
+28 60497323 3 8
+28 188261423 1 7
+28 188261423 2 7
+28 188261423 3 7
+28 140541072 1 7
+28 140541072 2 7
+28 140541072 3 7
+28 33608837 1 3
+28 33608837 2 3
+28 33608837 3 3
+28 69772754 1 6
+28 69772754 2 6
+28 69772754 3 6
+28 231659097 1 0
+28 231659097 2 0
+28 231659097 3 0
+28 65708608 1 4
+28 65708608 2 4
+28 65708608 3 4
+28 27844939 1 5
+28 27844939 2 5
+28 27844939 3 5
+28 250016684 1 1
+28 250016684 2 1
+28 250016684 3 1
+28 27914189 1 3
+28 27914189 2 3
+28 27914189 3 3
+28 242637280 1 4
+28 242637280 2 4
+28 242637280 3 4
+28 100798268 1 3
+28 100798268 2 3
+28 100798268 3 3
+28 63664849 1 2
+28 63664849 2 2
+28 63664849 3 2
+28 186850612 1 2
+28 186850612 2 2
+28 186850612 3 2
+28 154249749 1 7
+28 154249749 2 7
+28 154249749 3 7
+28 90932767 1 8
+28 90932767 2 8
+28 90932767 3 8
+28 101133202 1 3
+28 101133202 2 3
+28 101133202 3 3
+28 161863951 1 4
+28 161863951 2 4
+28 161863951 3 4
+28 106351991 1 8
+28 106351991 2 8
+28 106351991 3 8
+28 164447437 1 6
+28 164447437 2 6
+28 164447437 3 6
+28 198321520 1 2
+28 198321520 2 2
+28 198321520 3 2
+28 66343474 1 5
+28 66343474 2 5
+28 66343474 3 5
+28 221986069 1 6
+28 221986069 2 6
+28 221986069 3 6
+28 19689396 1 0
+28 19689396 2 0
+28 19689396 3 0
+28 105945506 1 4
+28 105945506 2 4
+28 105945506 3 4
+28 153231939 1 1
+28 153231939 2 1
+28 153231939 3 1
+28 205884141 1 5
+28 205884141 2 5
+28 205884141 3 5
+28 101379925 1 7
+28 101379925 2 7
+28 101379925 3 7
+28 217838996 1 8
+28 217838996 2 8
+28 217838996 3 8
+28 146756671 1 4
+28 146756671 2 4
+28 146756671 3 4
+28 13896821 1 7
+28 13896821 2 7
+28 13896821 3 7
+28 262954695 1 0
+28 262954695 2 0
+28 262954695 3 0
+28 188329314 1 0
+28 188329314 2 0
+28 188329314 3 0
+28 166574838 1 4
+28 166574838 2 4
+28 166574838 3 4
+28 73291029 1 7
+28 73291029 2 7
+28 73291029 3 7
+28 60443185 1 3
+28 60443185 2 3
+28 60443185 3 3
+28 168418913 1 2
+28 168418913 2 2
+28 168418913 3 2
+28 106600330 1 4
+28 106600330 2 4
+28 106600330 3 4
+28 224100522 1 5
+28 224100522 2 5
+28 224100522 3 5
+28 50445651 1 7
+28 50445651 2 7
+28 50445651 3 7
+28 49791383 1 6
+28 49791383 2 6
+28 49791383 3 6
+28 56004596 1 7
+28 56004596 2 7
+28 56004596 3 7
+28 163008005 1 0
+28 163008005 2 0
+28 163008005 3 0
+28 130294270 1 8
+28 130294270 2 8
+28 130294270 3 8
+28 79031870 1 6
+28 79031870 2 6
+28 79031870 3 6
+28 8779135 1 7
+28 8779135 2 7
+28 8779135 3 7
+28 132122986 1 6
+28 132122986 2 6
+28 132122986 3 6
+28 106262167 1 2
+28 106262167 2 2
+28 106262167 3 2
+28 84962373 1 5
+28 84962373 2 5
+28 84962373 3 5
+28 149117771 1 2
+28 149117771 2 2
+28 149117771 3 2
+28 179783442 1 2
+28 179783442 2 2
+28 179783442 3 2
+29 335271491 1 5
+29 335271491 2 5
+29 335271491 3 5
+29 10720791 1 8
+29 10720791 2 8
+29 10720791 3 8
+29 500040308 1 6
+29 500040308 2 6
+29 500040308 3 6
+29 510755966 1 8
+29 510755966 2 8
+29 510755966 3 8
+29 227186933 1 5
+29 227186933 2 5
+29 227186933 3 5
+29 422662843 1 3
+29 422662843 2 3
+29 422662843 3 3
+29 81866932 1 8
+29 81866932 2 8
+29 81866932 3 8
+29 470195498 1 1
+29 470195498 2 1
+29 470195498 3 1
+29 505281812 1 5
+29 505281812 2 5
+29 505281812 3 5
+29 42328055 1 5
+29 42328055 2 5
+29 42328055 3 5
+29 510604597 1 6
+29 510604597 2 6
+29 510604597 3 6
+29 380926471 1 4
+29 380926471 2 4
+29 380926471 3 4
+29 159591288 1 8
+29 159591288 2 8
+29 159591288 3 8
+29 189495832 1 5
+29 189495832 2 5
+29 189495832 3 5
+29 7461185 1 1
+29 7461185 2 1
+29 7461185 3 1
+29 41392678 1 5
+29 41392678 2 5
+29 41392678 3 5
+29 466412287 1 4
+29 466412287 2 4
+29 466412287 3 4
+29 269683984 1 8
+29 269683984 2 8
+29 269683984 3 8
+29 81614953 1 7
+29 81614953 2 7
+29 81614953 3 7
+29 117179003 1 4
+29 117179003 2 4
+29 117179003 3 4
+29 348566793 1 8
+29 348566793 2 8
+29 348566793 3 8
+29 502596854 1 4
+29 502596854 2 4
+29 502596854 3 4
+29 364569853 1 7
+29 364569853 2 7
+29 364569853 3 7
+29 262837855 1 8
+29 262837855 2 8
+29 262837855 3 8
+29 316887548 1 3
+29 316887548 2 3
+29 316887548 3 3
+29 223063684 1 3
+29 223063684 2 3
+29 223063684 3 3
+29 459226263 1 2
+29 459226263 2 2
+29 459226263 3 2
+29 299433996 1 8
+29 299433996 2 8
+29 299433996 3 8
+29 200795585 1 1
+29 200795585 2 1
+29 200795585 3 1
+29 136914840 1 5
+29 136914840 2 5
+29 136914840 3 5
+29 237980817 1 4
+29 237980817 2 4
+29 237980817 3 4
+29 350103844 1 8
+29 350103844 2 8
+29 350103844 3 8
+29 441877573 1 1
+29 441877573 2 1
+29 441877573 3 1
+29 40558515 1 6
+29 40558515 2 6
+29 40558515 3 6
+29 161801865 1 7
+29 161801865 2 7
+29 161801865 3 7
+29 504185643 1 7
+29 504185643 2 7
+29 504185643 3 7
+29 85566969 1 3
+29 85566969 2 3
+29 85566969 3 3
+29 59549821 1 7
+29 59549821 2 7
+29 59549821 3 7
+29 42304740 1 8
+29 42304740 2 8
+29 42304740 3 8
+29 14245896 1 8
+29 14245896 2 8
+29 14245896 3 8
+29 313701459 1 8
+29 313701459 2 8
+29 313701459 3 8
+29 77420095 1 3
+29 77420095 2 3
+29 77420095 3 3
+29 243081033 1 7
+29 243081033 2 7
+29 243081033 3 7
+29 430152328 1 4
+29 430152328 2 4
+29 430152328 3 4
+29 84780619 1 4
+29 84780619 2 4
+29 84780619 3 4
+29 251064423 1 5
+29 251064423 2 5
+29 251064423 3 5
+29 529469218 1 7
+29 529469218 2 7
+29 529469218 3 7
+29 133549787 1 5
+29 133549787 2 5
+29 133549787 3 5
+29 383495391 1 7
+29 383495391 2 7
+29 383495391 3 7
+29 446460424 1 8
+29 446460424 2 8
+29 446460424 3 8
+29 302973982 1 1
+29 302973982 2 1
+29 302973982 3 1
+29 321643285 1 2
+29 321643285 2 2
+29 321643285 3 2
+29 299298703 1 4
+29 299298703 2 4
+29 299298703 3 4
+29 90118743 1 5
+29 90118743 2 5
+29 90118743 3 5
+29 269748402 1 5
+29 269748402 2 5
+29 269748402 3 5
+29 47030190 1 8
+29 47030190 2 8
+29 47030190 3 8
+29 504453345 1 6
+29 504453345 2 6
+29 504453345 3 6
+29 506285359 1 6
+29 506285359 2 6
+29 506285359 3 6
+29 429364883 1 6
+29 429364883 2 6
+29 429364883 3 6
+29 437983235 1 7
+29 437983235 2 7
+29 437983235 3 7
+29 446722782 1 1
+29 446722782 2 1
+29 446722782 3 1
+29 170722190 1 8
+29 170722190 2 8
+29 170722190 3 8
+29 347257661 1 6
+29 347257661 2 6
+29 347257661 3 6
+29 344826579 1 3
+29 344826579 2 3
+29 344826579 3 3
+30 213793736 1 7
+30 213793736 2 7
+30 213793736 3 7
+30 841563124 1 5
+30 841563124 2 5
+30 841563124 3 5
+30 497541093 1 7
+30 497541093 2 7
+30 497541093 3 7
+30 886071695 1 7
+30 886071695 2 7
+30 886071695 3 7
+30 442450336 1 1
+30 442450336 2 1
+30 442450336 3 1
+30 359840809 1 8
+30 359840809 2 8
+30 359840809 3 8
+30 237523472 1 7
+30 237523472 2 7
+30 237523472 3 7
+30 841255244 1 8
+30 841255244 2 8
+30 841255244 3 8
+30 254748983 1 8
+30 254748983 2 8
+30 254748983 3 8
+30 888089982 1 7
+30 888089982 2 7
+30 888089982 3 7
+30 514507124 1 3
+30 514507124 2 3
+30 514507124 3 3
+30 954375894 1 7
+30 954375894 2 7
+30 954375894 3 7
+30 313226812 1 5
+30 313226812 2 5
+30 313226812 3 5
+30 339371217 1 1
+30 339371217 2 1
+30 339371217 3 1
+30 818297353 1 4
+30 818297353 2 4
+30 818297353 3 4
+30 70402405 1 7
+30 70402405 2 7
+30 70402405 3 7
+30 778614673 1 7
+30 778614673 2 7
+30 778614673 3 7
+30 475256662 1 7
+30 475256662 2 7
+30 475256662 3 7
+30 263311931 1 5
+30 263311931 2 5
+30 263311931 3 5
+30 499638729 1 8
+30 499638729 2 8
+30 499638729 3 8
+30 191707598 1 2
+30 191707598 2 2
+30 191707598 3 2
+30 13291798 1 6
+30 13291798 2 6
+30 13291798 3 6
+30 428344683 1 2
+30 428344683 2 2
+30 428344683 3 2
+30 470671586 1 2
+30 470671586 2 2
+30 470671586 3 2
+30 1010796989 1 3
+30 1010796989 2 3
+30 1010796989 3 3
+30 550173547 1 8
+30 550173547 2 8
+30 550173547 3 8
+30 984276590 1 7
+30 984276590 2 7
+30 984276590 3 7
+30 400752165 1 0
+30 400752165 2 0
+30 400752165 3 0
+30 676513500 1 0
+30 676513500 2 0
+30 676513500 3 0
+30 29569926 1 7
+30 29569926 2 7
+30 29569926 3 7
+30 814936588 1 2
+30 814936588 2 2
+30 814936588 3 2
+30 424154654 1 8
+30 424154654 2 8
+30 424154654 3 8
+30 414893534 1 6
+30 414893534 2 6
+30 414893534 3 6
+30 1050718441 1 6
+30 1050718441 2 6
+30 1050718441 3 6
+30 680733058 1 8
+30 680733058 2 8
+30 680733058 3 8
+30 194457832 1 6
+30 194457832 2 6
+30 194457832 3 6
+30 961676074 1 1
+30 961676074 2 1
+30 961676074 3 1
+30 735607789 1 6
+30 735607789 2 6
+30 735607789 3 6
+30 375086337 1 3
+30 375086337 2 3
+30 375086337 3 3
+30 52289719 1 7
+30 52289719 2 7
+30 52289719 3 7
+30 482043226 1 1
+30 482043226 2 1
+30 482043226 3 1
+30 1035547710 1 4
+30 1035547710 2 4
+30 1035547710 3 4
+30 222543404 1 3
+30 222543404 2 3
+30 222543404 3 3
+30 1060433998 1 8
+30 1060433998 2 8
+30 1060433998 3 8
+30 887738302 1 4
+30 887738302 2 4
+30 887738302 3 4
+30 868165466 1 7
+30 868165466 2 7
+30 868165466 3 7
+30 1051398814 1 8
+30 1051398814 2 8
+30 1051398814 3 8
+30 489644425 1 6
+30 489644425 2 6
+30 489644425 3 6
+30 1024951511 1 1
+30 1024951511 2 1
+30 1024951511 3 1
+30 686077717 1 2
+30 686077717 2 2
+30 686077717 3 2
+30 1056030306 1 8
+30 1056030306 2 8
+30 1056030306 3 8
+30 565885909 1 8
+30 565885909 2 8
+30 565885909 3 8
+30 89610460 1 0
+30 89610460 2 0
+30 89610460 3 0
+30 774443031 1 6
+30 774443031 2 6
+30 774443031 3 6
+30 433823353 1 3
+30 433823353 2 3
+30 433823353 3 3
+30 394963635 1 1
+30 394963635 2 1
+30 394963635 3 1
+30 724153400 1 2
+30 724153400 2 2
+30 724153400 3 2
+30 29831260 1 4
+30 29831260 2 4
+30 29831260 3 4
+30 241349464 1 6
+30 241349464 2 6
+30 241349464 3 6
+30 57273401 1 1
+30 57273401 2 1
+30 57273401 3 1
+30 230647305 1 2
+30 230647305 2 2
+30 230647305 3 2
+30 181878195 1 1
+30 181878195 2 1
+30 181878195 3 1
+30 21273447 1 4
+30 21273447 2 4
+30 21273447 3 4
+30 386568080 1 4
+30 386568080 2 4
+30 386568080 3 4
+31 433243292 1 8
+31 433243292 2 8
+31 433243292 3 8
+31 743572650 1 4
+31 743572650 2 4
+31 743572650 3 4
+31 1751072959 1 1
+31 1751072959 2 1
+31 1751072959 3 1
+31 582009481 1 8
+31 582009481 2 8
+31 582009481 3 8
+31 1086523751 1 5
+31 1086523751 2 5
+31 1086523751 3 5
+31 1633480282 1 4
+31 1633480282 2 4
+31 1633480282 3 4
+31 543551900 1 8
+31 543551900 2 8
+31 543551900 3 8
+31 359654721 1 6
+31 359654721 2 6
+31 359654721 3 6
+31 517216897 1 8
+31 517216897 2 8
+31 517216897 3 8
+31 1321997222 1 3
+31 1321997222 2 3
+31 1321997222 3 3
+31 1765905076 1 3
+31 1765905076 2 3
+31 1765905076 3 3
+31 1658010939 1 6
+31 1658010939 2 6
+31 1658010939 3 6
+31 798885882 1 3
+31 798885882 2 3
+31 798885882 3 3
+31 1542111550 1 4
+31 1542111550 2 4
+31 1542111550 3 4
+31 1979674396 1 7
+31 1979674396 2 7
+31 1979674396 3 7
+31 1313431291 1 7
+31 1313431291 2 7
+31 1313431291 3 7
+31 1748289035 1 6
+31 1748289035 2 6
+31 1748289035 3 6
+31 2017345172 1 7
+31 2017345172 2 7
+31 2017345172 3 7
+31 1992315978 1 1
+31 1992315978 2 1
+31 1992315978 3 1
+31 1624850948 1 8
+31 1624850948 2 8
+31 1624850948 3 8
+31 780864908 1 1
+31 780864908 2 1
+31 780864908 3 1
+31 534307425 1 7
+31 534307425 2 7
+31 534307425 3 7
+31 1301871260 1 4
+31 1301871260 2 4
+31 1301871260 3 4
+31 222436705 1 6
+31 222436705 2 6
+31 222436705 3 6
+31 421579900 1 7
+31 421579900 2 7
+31 421579900 3 7
+31 2051749662 1 8
+31 2051749662 2 8
+31 2051749662 3 8
+31 1525087697 1 1
+31 1525087697 2 1
+31 1525087697 3 1
+31 9065501 1 4
+31 9065501 2 4
+31 9065501 3 4
+31 1054811774 1 8
+31 1054811774 2 8
+31 1054811774 3 8
+31 1675964300 1 5
+31 1675964300 2 5
+31 1675964300 3 5
+31 85747085 1 7
+31 85747085 2 7
+31 85747085 3 7
+31 2010083787 1 3
+31 2010083787 2 3
+31 2010083787 3 3
+31 960759126 1 4
+31 960759126 2 4
+31 960759126 3 4
+31 892955437 1 7
+31 892955437 2 7
+31 892955437 3 7
+31 1581497818 1 3
+31 1581497818 2 3
+31 1581497818 3 3
+31 2087270142 1 4
+31 2087270142 2 4
+31 2087270142 3 4
+31 1564424559 1 8
+31 1564424559 2 8
+31 1564424559 3 8
+31 1762953928 1 3
+31 1762953928 2 3
+31 1762953928 3 3
+31 264159138 1 6
+31 264159138 2 6
+31 264159138 3 6
+31 934393298 1 5
+31 934393298 2 5
+31 934393298 3 5
+31 425929304 1 8
+31 425929304 2 8
+31 425929304 3 8
+31 1431999721 1 7
+31 1431999721 2 7
+31 1431999721 3 7
+31 50432310 1 0
+31 50432310 2 0
+31 50432310 3 0
+31 671383138 1 6
+31 671383138 2 6
+31 671383138 3 6
+31 1514870594 1 7
+31 1514870594 2 7
+31 1514870594 3 7
+31 125594206 1 8
+31 125594206 2 8
+31 125594206 3 8
+31 340551370 1 4
+31 340551370 2 4
+31 340551370 3 4
+31 1623645007 1 1
+31 1623645007 2 1
+31 1623645007 3 1
+31 1348003716 1 7
+31 1348003716 2 7
+31 1348003716 3 7
+31 2037861051 1 4
+31 2037861051 2 4
+31 2037861051 3 4
+31 2057710326 1 5
+31 2057710326 2 5
+31 2057710326 3 5
+31 663428672 1 7
+31 663428672 2 7
+31 663428672 3 7
+31 1949076248 1 2
+31 1949076248 2 2
+31 1949076248 3 2
+31 1083205847 1 2
+31 1083205847 2 2
+31 1083205847 3 2
+31 1989744438 1 0
+31 1989744438 2 0
+31 1989744438 3 0
+31 815856732 1 1
+31 815856732 2 1
+31 815856732 3 1
+31 829877019 1 8
+31 829877019 2 8
+31 829877019 3 8
+31 188649293 1 4
+31 188649293 2 4
+31 188649293 3 4
+31 1198806123 1 1
+31 1198806123 2 1
+31 1198806123 3 1
+31 1973746385 1 4
+31 1973746385 2 4
+31 1973746385 3 4
+31 839543376 1 4
+31 839543376 2 4
+31 839543376 3 4
+31 1072944380 1 7
+31 1072944380 2 7
+31 1072944380 3 7
+31 1561590617 1 4
+31 1561590617 2 4
+31 1561590617 3 4
+31 551611217 1 5
+31 551611217 2 5
+31 551611217 3 5
+32 1036684082 1 7
+32 1036684082 2 7
+32 1036684082 3 7
+32 2486634245 1 6
+32 2486634245 2 6
+32 2486634245 3 6
+32 1960853583 1 7
+32 1960853583 2 7
+32 1960853583 3 7
+32 2216609468 1 6
+32 2216609468 2 6
+32 2216609468 3 6
+32 221178161 1 3
+32 221178161 2 3
+32 221178161 3 3
+32 439758692 1 0
+32 439758692 2 0
+32 439758692 3 0
+32 1129185496 1 4
+32 1129185496 2 4
+32 1129185496 3 4
+32 1867788184 1 4
+32 1867788184 2 4
+32 1867788184 3 4
+32 564853289 1 6
+32 564853289 2 6
+32 564853289 3 6
+32 2344179581 1 5
+32 2344179581 2 5
+32 2344179581 3 5
+32 2970472705 1 0
+32 2970472705 2 0
+32 2970472705 3 0
+32 4070187504 1 5
+32 4070187504 2 5
+32 4070187504 3 5
+32 2662144140 1 7
+32 2662144140 2 7
+32 2662144140 3 7
+32 4167572734 1 7
+32 4167572734 2 7
+32 4167572734 3 7
+32 927210200 1 6
+32 927210200 2 6
+32 927210200 3 6
+32 2208343448 1 6
+32 2208343448 2 6
+32 2208343448 3 6
+32 2192760228 1 8
+32 2192760228 2 8
+32 2192760228 3 8
+32 2166303367 1 3
+32 2166303367 2 3
+32 2166303367 3 3
+32 3688439934 1 7
+32 3688439934 2 7
+32 3688439934 3 7
+32 308030109 1 5
+32 308030109 2 5
+32 308030109 3 5
+32 1104848908 1 6
+32 1104848908 2 6
+32 1104848908 3 6
+32 3705758252 1 4
+32 3705758252 2 4
+32 3705758252 3 4
+32 336358057 1 8
+32 336358057 2 8
+32 336358057 3 8
+32 701422524 1 8
+32 701422524 2 8
+32 701422524 3 8
+32 95384115 1 6
+32 95384115 2 6
+32 95384115 3 6
+32 3922974711 1 6
+32 3922974711 2 6
+32 3922974711 3 6
+32 60262178 1 5
+32 60262178 2 5
+32 60262178 3 5
+32 2696528104 1 5
+32 2696528104 2 5
+32 2696528104 3 5
+32 19462365 1 2
+32 19462365 2 2
+32 19462365 3 2
+32 2463013988 1 5
+32 2463013988 2 5
+32 2463013988 3 5
+32 1023022920 1 2
+32 1023022920 2 2
+32 1023022920 3 2
+32 3781145032 1 3
+32 3781145032 2 3
+32 3781145032 3 3
+32 1830433185 1 4
+32 1830433185 2 4
+32 1830433185 3 4
+32 424433380 1 1
+32 424433380 2 1
+32 424433380 3 1
+32 1623797388 1 6
+32 1623797388 2 6
+32 1623797388 3 6
+32 3401848886 1 8
+32 3401848886 2 8
+32 3401848886 3 8
+32 1317540203 1 5
+32 1317540203 2 5
+32 1317540203 3 5
+32 1120055386 1 1
+32 1120055386 2 1
+32 1120055386 3 1
+32 454820083 1 0
+32 454820083 2 0
+32 454820083 3 0
+32 1359971009 1 7
+32 1359971009 2 7
+32 1359971009 3 7
+32 497197820 1 7
+32 497197820 2 7
+32 497197820 3 7
+32 4289564065 1 8
+32 4289564065 2 8
+32 4289564065 3 8
+32 124772759 1 3
+32 124772759 2 3
+32 124772759 3 3
+32 1308886828 1 6
+32 1308886828 2 6
+32 1308886828 3 6
+32 3243928933 1 8
+32 3243928933 2 8
+32 3243928933 3 8
+32 3788970499 1 8
+32 3788970499 2 8
+32 3788970499 3 8
+32 4103967014 1 0
+32 4103967014 2 0
+32 4103967014 3 0
+32 1705735405 1 4
+32 1705735405 2 4
+32 1705735405 3 4
+32 416033424 1 7
+32 416033424 2 7
+32 416033424 3 7
+32 514236867 1 4
+32 514236867 2 4
+32 514236867 3 4
+32 3686390881 1 4
+32 3686390881 2 4
+32 3686390881 3 4
+32 2125027247 1 6
+32 2125027247 2 6
+32 2125027247 3 6
+32 2029833655 1 1
+32 2029833655 2 1
+32 2029833655 3 1
+32 3917495445 1 6
+32 3917495445 2 6
+32 3917495445 3 6
+32 2650507935 1 5
+32 2650507935 2 5
+32 2650507935 3 5
+32 282773968 1 8
+32 282773968 2 8
+32 282773968 3 8
+32 446683627 1 6
+32 446683627 2 6
+32 446683627 3 6
+32 2843691041 1 6
+32 2843691041 2 6
+32 2843691041 3 6
+32 1191222343 1 8
+32 1191222343 2 8
+32 1191222343 3 8
+32 2016286435 1 8
+32 2016286435 2 8
+32 2016286435 3 8
+32 1893861518 1 7
+32 1893861518 2 7
+32 1893861518 3 7
+32 3977622147 1 8
+32 3977622147 2 8
+32 3977622147 3 8
+32 571267417 1 1
+32 571267417 2 1
+32 571267417 3 1
+32 2363239984 1 5
+32 2363239984 2 5
+32 2363239984 3 5
diff --git a/vdslib/src/tests/distribution/testdata/java_depth2.state b/vdslib/src/tests/distribution/testdata/java_depth2.state
new file mode 100644
index 00000000000..0be8744eced
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/java_depth2.state
@@ -0,0 +1 @@
+distributor:9 \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/java_depth3.cfg b/vdslib/src/tests/distribution/testdata/java_depth3.cfg
new file mode 100644
index 00000000000..fc0e597013d
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/java_depth3.cfg
@@ -0,0 +1,46 @@
+redundancy 5
+group[7]
+group[0].partitions "*|*"
+group[0].index "invalid"
+group[0].name "invalid"
+group[0].nodes[0]
+group[1].partitions "1|*"
+group[1].index "0"
+group[1].name "switch0"
+group[1].nodes[0]
+group[2].partitions ""
+group[2].index "0.0"
+group[2].name "rack0"
+group[2].nodes[4]
+group[2].nodes[0].index 0
+group[2].nodes[1].index 1
+group[2].nodes[2].index 2
+group[2].nodes[3].index 3
+group[3].partitions ""
+group[3].index "0.1"
+group[3].name "rack1"
+group[3].nodes[4]
+group[3].nodes[0].index 8
+group[3].nodes[1].index 9
+group[3].nodes[2].index 14
+group[3].nodes[3].index 15
+group[4].partitions "*"
+group[4].index "1"
+group[4].name "switch1"
+group[4].nodes[0]
+group[5].partitions ""
+group[5].index "1.0"
+group[5].name "rack0"
+group[5].nodes[4]
+group[5].nodes[0].index 4
+group[5].nodes[1].index 5
+group[5].nodes[2].index 6
+group[5].nodes[3].index 17
+group[6].partitions ""
+group[6].index "1.1"
+group[6].name "rack1"
+group[6].nodes[4]
+group[6].nodes[0].index 10
+group[6].nodes[1].index 12
+group[6].nodes[2].index 13
+group[6].nodes[3].index 7 \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/java_depth3.distribution b/vdslib/src/tests/distribution/testdata/java_depth3.distribution
new file mode 100644
index 00000000000..1087c796fd7
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/java_depth3.distribution
@@ -0,0 +1,8955 @@
+0 0 1 6
+0 0 2 6
+0 0 3 6
+0 0 4 6
+0 0 5 6
+1 0 1 6
+1 0 2 6
+1 0 3 6
+1 0 4 6
+1 0 5 6
+1 1 1 8
+1 1 2 8
+1 1 3 8
+1 1 4 8
+1 1 5 8
+2 0 1 6
+2 0 2 6
+2 0 3 6
+2 0 4 6
+2 0 5 6
+2 1 1 8
+2 1 2 8
+2 1 3 8
+2 1 4 8
+2 1 5 8
+2 2 1 2
+2 2 2 2
+2 2 3 2
+2 2 4 2
+2 2 5 2
+2 3 1 5
+2 3 2 5
+2 3 3 5
+2 3 4 5
+2 3 5 5
+3 0 1 6
+3 0 2 6
+3 0 3 6
+3 0 4 6
+3 0 5 6
+3 1 1 8
+3 1 2 8
+3 1 3 8
+3 1 4 8
+3 1 5 8
+3 2 1 2
+3 2 2 2
+3 2 3 2
+3 2 4 2
+3 2 5 2
+3 3 1 5
+3 3 2 5
+3 3 3 5
+3 3 4 5
+3 3 5 5
+3 4 1 12
+3 4 2 12
+3 4 3 12
+3 4 4 12
+3 4 5 12
+3 5 1 6
+3 5 2 6
+3 5 3 6
+3 5 4 6
+3 5 5 6
+3 6 1 8
+3 6 2 8
+3 6 3 8
+3 6 4 8
+3 6 5 8
+3 7 1 2
+3 7 2 2
+3 7 3 2
+3 7 4 2
+3 7 5 2
+4 0 1 6
+4 0 2 6
+4 0 3 6
+4 0 4 6
+4 0 5 6
+4 1 1 8
+4 1 2 8
+4 1 3 8
+4 1 4 8
+4 1 5 8
+4 2 1 2
+4 2 2 2
+4 2 3 2
+4 2 4 2
+4 2 5 2
+4 3 1 5
+4 3 2 5
+4 3 3 5
+4 3 4 5
+4 3 5 5
+4 4 1 12
+4 4 2 12
+4 4 3 12
+4 4 4 12
+4 4 5 12
+4 5 1 6
+4 5 2 6
+4 5 3 6
+4 5 4 6
+4 5 5 6
+4 6 1 8
+4 6 2 8
+4 6 3 8
+4 6 4 8
+4 6 5 8
+4 7 1 2
+4 7 2 2
+4 7 3 2
+4 7 4 2
+4 7 5 2
+4 8 1 8
+4 8 2 8
+4 8 3 8
+4 8 4 8
+4 8 5 8
+4 9 1 5
+4 9 2 5
+4 9 3 5
+4 9 4 5
+4 9 5 5
+4 10 1 13
+4 10 2 13
+4 10 3 13
+4 10 4 13
+4 10 5 13
+4 11 1 6
+4 11 2 6
+4 11 3 6
+4 11 4 6
+4 11 5 6
+4 12 1 6
+4 12 2 6
+4 12 3 6
+4 12 4 6
+4 12 5 6
+4 13 1 8
+4 13 2 8
+4 13 3 8
+4 13 4 8
+4 13 5 8
+4 14 1 0
+4 14 2 0
+4 14 3 0
+4 14 4 0
+4 14 5 0
+4 15 1 5
+4 15 2 5
+4 15 3 5
+4 15 4 5
+4 15 5 5
+5 0 1 6
+5 0 2 6
+5 0 3 6
+5 0 4 6
+5 0 5 6
+5 1 1 8
+5 1 2 8
+5 1 3 8
+5 1 4 8
+5 1 5 8
+5 2 1 2
+5 2 2 2
+5 2 3 2
+5 2 4 2
+5 2 5 2
+5 3 1 5
+5 3 2 5
+5 3 3 5
+5 3 4 5
+5 3 5 5
+5 4 1 12
+5 4 2 12
+5 4 3 12
+5 4 4 12
+5 4 5 12
+5 5 1 6
+5 5 2 6
+5 5 3 6
+5 5 4 6
+5 5 5 6
+5 6 1 8
+5 6 2 8
+5 6 3 8
+5 6 4 8
+5 6 5 8
+5 7 1 2
+5 7 2 2
+5 7 3 2
+5 7 4 2
+5 7 5 2
+5 8 1 8
+5 8 2 8
+5 8 3 8
+5 8 4 8
+5 8 5 8
+5 9 1 5
+5 9 2 5
+5 9 3 5
+5 9 4 5
+5 9 5 5
+5 10 1 13
+5 10 2 13
+5 10 3 13
+5 10 4 13
+5 10 5 13
+5 11 1 6
+5 11 2 6
+5 11 3 6
+5 11 4 6
+5 11 5 6
+5 12 1 6
+5 12 2 6
+5 12 3 6
+5 12 4 6
+5 12 5 6
+5 13 1 8
+5 13 2 8
+5 13 3 8
+5 13 4 8
+5 13 5 8
+5 14 1 0
+5 14 2 0
+5 14 3 0
+5 14 4 0
+5 14 5 0
+5 15 1 5
+5 15 2 5
+5 15 3 5
+5 15 4 5
+5 15 5 5
+5 16 1 7
+5 16 2 7
+5 16 3 7
+5 16 4 7
+5 16 5 7
+5 17 1 7
+5 17 2 7
+5 17 3 7
+5 17 4 7
+5 17 5 7
+5 18 1 17
+5 18 2 17
+5 18 3 17
+5 18 4 17
+5 18 5 17
+5 19 1 1
+5 19 2 1
+5 19 3 1
+5 19 4 1
+5 19 5 1
+5 20 1 8
+5 20 2 8
+5 20 3 8
+5 20 4 8
+5 20 5 8
+5 21 1 4
+5 21 2 4
+5 21 3 4
+5 21 4 4
+5 21 5 4
+5 22 1 4
+5 22 2 4
+5 22 3 4
+5 22 4 4
+5 22 5 4
+5 23 1 5
+5 23 2 5
+5 23 3 5
+5 23 4 5
+5 23 5 5
+5 24 1 0
+5 24 2 0
+5 24 3 0
+5 24 4 0
+5 24 5 0
+5 25 1 17
+5 25 2 17
+5 25 3 17
+5 25 4 17
+5 25 5 17
+5 26 1 8
+5 26 2 8
+5 26 3 8
+5 26 4 8
+5 26 5 8
+5 27 1 12
+5 27 2 12
+5 27 3 12
+5 27 4 12
+5 27 5 12
+5 28 1 7
+5 28 2 7
+5 28 3 7
+5 28 4 7
+5 28 5 7
+5 29 1 1
+5 29 2 1
+5 29 3 1
+5 29 4 1
+5 29 5 1
+5 30 1 10
+5 30 2 10
+5 30 3 10
+5 30 4 10
+5 30 5 10
+5 31 1 8
+5 31 2 8
+5 31 3 8
+5 31 4 8
+5 31 5 8
+6 0 1 6
+6 0 2 6
+6 0 3 6
+6 0 4 6
+6 0 5 6
+6 1 1 8
+6 1 2 8
+6 1 3 8
+6 1 4 8
+6 1 5 8
+6 2 1 2
+6 2 2 2
+6 2 3 2
+6 2 4 2
+6 2 5 2
+6 3 1 5
+6 3 2 5
+6 3 3 5
+6 3 4 5
+6 3 5 5
+6 4 1 12
+6 4 2 12
+6 4 3 12
+6 4 4 12
+6 4 5 12
+6 5 1 6
+6 5 2 6
+6 5 3 6
+6 5 4 6
+6 5 5 6
+6 6 1 8
+6 6 2 8
+6 6 3 8
+6 6 4 8
+6 6 5 8
+6 7 1 2
+6 7 2 2
+6 7 3 2
+6 7 4 2
+6 7 5 2
+6 8 1 8
+6 8 2 8
+6 8 3 8
+6 8 4 8
+6 8 5 8
+6 9 1 5
+6 9 2 5
+6 9 3 5
+6 9 4 5
+6 9 5 5
+6 10 1 13
+6 10 2 13
+6 10 3 13
+6 10 4 13
+6 10 5 13
+6 11 1 6
+6 11 2 6
+6 11 3 6
+6 11 4 6
+6 11 5 6
+6 12 1 6
+6 12 2 6
+6 12 3 6
+6 12 4 6
+6 12 5 6
+6 13 1 8
+6 13 2 8
+6 13 3 8
+6 13 4 8
+6 13 5 8
+6 14 1 0
+6 14 2 0
+6 14 3 0
+6 14 4 0
+6 14 5 0
+6 15 1 5
+6 15 2 5
+6 15 3 5
+6 15 4 5
+6 15 5 5
+6 16 1 7
+6 16 2 7
+6 16 3 7
+6 16 4 7
+6 16 5 7
+6 17 1 7
+6 17 2 7
+6 17 3 7
+6 17 4 7
+6 17 5 7
+6 18 1 17
+6 18 2 17
+6 18 3 17
+6 18 4 17
+6 18 5 17
+6 19 1 1
+6 19 2 1
+6 19 3 1
+6 19 4 1
+6 19 5 1
+6 20 1 8
+6 20 2 8
+6 20 3 8
+6 20 4 8
+6 20 5 8
+6 21 1 4
+6 21 2 4
+6 21 3 4
+6 21 4 4
+6 21 5 4
+6 22 1 4
+6 22 2 4
+6 22 3 4
+6 22 4 4
+6 22 5 4
+6 23 1 5
+6 23 2 5
+6 23 3 5
+6 23 4 5
+6 23 5 5
+6 24 1 0
+6 24 2 0
+6 24 3 0
+6 24 4 0
+6 24 5 0
+6 25 1 17
+6 25 2 17
+6 25 3 17
+6 25 4 17
+6 25 5 17
+6 26 1 8
+6 26 2 8
+6 26 3 8
+6 26 4 8
+6 26 5 8
+6 27 1 12
+6 27 2 12
+6 27 3 12
+6 27 4 12
+6 27 5 12
+6 28 1 7
+6 28 2 7
+6 28 3 7
+6 28 4 7
+6 28 5 7
+6 29 1 1
+6 29 2 1
+6 29 3 1
+6 29 4 1
+6 29 5 1
+6 30 1 10
+6 30 2 10
+6 30 3 10
+6 30 4 10
+6 30 5 10
+6 31 1 8
+6 31 2 8
+6 31 3 8
+6 31 4 8
+6 31 5 8
+6 32 1 5
+6 32 2 5
+6 32 3 5
+6 32 4 5
+6 32 5 5
+6 33 1 12
+6 33 2 12
+6 33 3 12
+6 33 4 12
+6 33 5 12
+6 34 1 1
+6 34 2 1
+6 34 3 1
+6 34 4 1
+6 34 5 1
+6 35 1 7
+6 35 2 7
+6 35 3 7
+6 35 4 7
+6 35 5 7
+6 36 1 3
+6 36 2 3
+6 36 3 3
+6 36 4 3
+6 36 5 3
+6 37 1 5
+6 37 2 5
+6 37 3 5
+6 37 4 5
+6 37 5 5
+6 38 1 3
+6 38 2 3
+6 38 3 3
+6 38 4 3
+6 38 5 3
+6 39 1 4
+6 39 2 4
+6 39 3 4
+6 39 4 4
+6 39 5 4
+6 40 1 5
+6 40 2 5
+6 40 3 5
+6 40 4 5
+6 40 5 5
+6 41 1 3
+6 41 2 3
+6 41 3 3
+6 41 4 3
+6 41 5 3
+6 42 1 4
+6 42 2 4
+6 42 3 4
+6 42 4 4
+6 42 5 4
+6 43 1 1
+6 43 2 1
+6 43 3 1
+6 43 4 1
+6 43 5 1
+6 44 1 8
+6 44 2 8
+6 44 3 8
+6 44 4 8
+6 44 5 8
+6 45 1 10
+6 45 2 10
+6 45 3 10
+6 45 4 10
+6 45 5 10
+6 46 1 5
+6 46 2 5
+6 46 3 5
+6 46 4 5
+6 46 5 5
+6 47 1 7
+6 47 2 7
+6 47 3 7
+6 47 4 7
+6 47 5 7
+6 48 1 0
+6 48 2 0
+6 48 3 0
+6 48 4 0
+6 48 5 0
+6 49 1 8
+6 49 2 8
+6 49 3 8
+6 49 4 8
+6 49 5 8
+6 50 1 9
+6 50 2 9
+6 50 3 9
+6 50 4 9
+6 50 5 9
+6 51 1 7
+6 51 2 7
+6 51 3 7
+6 51 4 7
+6 51 5 7
+6 52 1 13
+6 52 2 13
+6 52 3 13
+6 52 4 13
+6 52 5 13
+6 53 1 10
+6 53 2 10
+6 53 3 10
+6 53 4 10
+6 53 5 10
+6 54 1 1
+6 54 2 1
+6 54 3 1
+6 54 4 1
+6 54 5 1
+6 55 1 8
+6 55 2 8
+6 55 3 8
+6 55 4 8
+6 55 5 8
+6 56 1 8
+6 56 2 8
+6 56 3 8
+6 56 4 8
+6 56 5 8
+6 57 1 6
+6 57 2 6
+6 57 3 6
+6 57 4 6
+6 57 5 6
+6 58 1 6
+6 58 2 6
+6 58 3 6
+6 58 4 6
+6 58 5 6
+6 59 1 1
+6 59 2 1
+6 59 3 1
+6 59 4 1
+6 59 5 1
+6 60 1 6
+6 60 2 6
+6 60 3 6
+6 60 4 6
+6 60 5 6
+6 61 1 3
+6 61 2 3
+6 61 3 3
+6 61 4 3
+6 61 5 3
+6 62 1 10
+6 62 2 10
+6 62 3 10
+6 62 4 10
+6 62 5 10
+6 63 1 13
+6 63 2 13
+6 63 3 13
+6 63 4 13
+6 63 5 13
+7 57 1 6
+7 57 2 6
+7 57 3 6
+7 57 4 6
+7 57 5 6
+7 93 1 12
+7 93 2 12
+7 93 3 12
+7 93 4 12
+7 93 5 12
+7 18 1 17
+7 18 2 17
+7 18 3 17
+7 18 4 17
+7 18 5 17
+7 93 1 12
+7 93 2 12
+7 93 3 12
+7 93 4 12
+7 93 5 12
+7 33 1 12
+7 33 2 12
+7 33 3 12
+7 33 4 12
+7 33 5 12
+7 95 1 2
+7 95 2 2
+7 95 3 2
+7 95 4 2
+7 95 5 2
+7 124 1 0
+7 124 2 0
+7 124 3 0
+7 124 4 0
+7 124 5 0
+7 101 1 3
+7 101 2 3
+7 101 3 3
+7 101 4 3
+7 101 5 3
+7 78 1 7
+7 78 2 7
+7 78 3 7
+7 78 4 7
+7 78 5 7
+7 105 1 14
+7 105 2 14
+7 105 3 14
+7 105 4 14
+7 105 5 14
+7 55 1 8
+7 55 2 8
+7 55 3 8
+7 55 4 8
+7 55 5 8
+7 105 1 14
+7 105 2 14
+7 105 3 14
+7 105 4 14
+7 105 5 14
+7 113 1 8
+7 113 2 8
+7 113 3 8
+7 113 4 8
+7 113 5 8
+7 38 1 3
+7 38 2 3
+7 38 3 3
+7 38 4 3
+7 38 5 3
+7 51 1 7
+7 51 2 7
+7 51 3 7
+7 51 4 7
+7 51 5 7
+7 39 1 4
+7 39 2 4
+7 39 3 4
+7 39 4 4
+7 39 5 4
+7 89 1 14
+7 89 2 14
+7 89 3 14
+7 89 4 14
+7 89 5 14
+7 4 1 12
+7 4 2 12
+7 4 3 12
+7 4 4 12
+7 4 5 12
+7 68 1 6
+7 68 2 6
+7 68 3 6
+7 68 4 6
+7 68 5 6
+7 96 1 4
+7 96 2 4
+7 96 3 4
+7 96 4 4
+7 96 5 4
+7 126 1 10
+7 126 2 10
+7 126 3 10
+7 126 4 10
+7 126 5 10
+7 54 1 1
+7 54 2 1
+7 54 3 1
+7 54 4 1
+7 54 5 1
+7 34 1 1
+7 34 2 1
+7 34 3 1
+7 34 4 1
+7 34 5 1
+7 89 1 14
+7 89 2 14
+7 89 3 14
+7 89 4 14
+7 89 5 14
+7 122 1 2
+7 122 2 2
+7 122 3 2
+7 122 4 2
+7 122 5 2
+7 53 1 10
+7 53 2 10
+7 53 3 10
+7 53 4 10
+7 53 5 10
+7 105 1 14
+7 105 2 14
+7 105 3 14
+7 105 4 14
+7 105 5 14
+7 90 1 2
+7 90 2 2
+7 90 3 2
+7 90 4 2
+7 90 5 2
+7 11 1 6
+7 11 2 6
+7 11 3 6
+7 11 4 6
+7 11 5 6
+7 59 1 1
+7 59 2 1
+7 59 3 1
+7 59 4 1
+7 59 5 1
+7 26 1 8
+7 26 2 8
+7 26 3 8
+7 26 4 8
+7 26 5 8
+7 50 1 9
+7 50 2 9
+7 50 3 9
+7 50 4 9
+7 50 5 9
+7 19 1 1
+7 19 2 1
+7 19 3 1
+7 19 4 1
+7 19 5 1
+7 70 1 0
+7 70 2 0
+7 70 3 0
+7 70 4 0
+7 70 5 0
+7 25 1 17
+7 25 2 17
+7 25 3 17
+7 25 4 17
+7 25 5 17
+7 48 1 0
+7 48 2 0
+7 48 3 0
+7 48 4 0
+7 48 5 0
+7 24 1 0
+7 24 2 0
+7 24 3 0
+7 24 4 0
+7 24 5 0
+7 27 1 12
+7 27 2 12
+7 27 3 12
+7 27 4 12
+7 27 5 12
+7 44 1 8
+7 44 2 8
+7 44 3 8
+7 44 4 8
+7 44 5 8
+7 44 1 8
+7 44 2 8
+7 44 3 8
+7 44 4 8
+7 44 5 8
+7 68 1 6
+7 68 2 6
+7 68 3 6
+7 68 4 6
+7 68 5 6
+7 65 1 1
+7 65 2 1
+7 65 3 1
+7 65 4 1
+7 65 5 1
+7 2 1 2
+7 2 2 2
+7 2 3 2
+7 2 4 2
+7 2 5 2
+7 124 1 0
+7 124 2 0
+7 124 3 0
+7 124 4 0
+7 124 5 0
+7 101 1 3
+7 101 2 3
+7 101 3 3
+7 101 4 3
+7 101 5 3
+7 2 1 2
+7 2 2 2
+7 2 3 2
+7 2 4 2
+7 2 5 2
+7 42 1 4
+7 42 2 4
+7 42 3 4
+7 42 4 4
+7 42 5 4
+7 127 1 2
+7 127 2 2
+7 127 3 2
+7 127 4 2
+7 127 5 2
+7 110 1 3
+7 110 2 3
+7 110 3 3
+7 110 4 3
+7 110 5 3
+7 109 1 17
+7 109 2 17
+7 109 3 17
+7 109 4 17
+7 109 5 17
+7 24 1 0
+7 24 2 0
+7 24 3 0
+7 24 4 0
+7 24 5 0
+7 22 1 4
+7 22 2 4
+7 22 3 4
+7 22 4 4
+7 22 5 4
+7 117 1 0
+7 117 2 0
+7 117 3 0
+7 117 4 0
+7 117 5 0
+7 87 1 0
+7 87 2 0
+7 87 3 0
+7 87 4 0
+7 87 5 0
+7 35 1 7
+7 35 2 7
+7 35 3 7
+7 35 4 7
+7 35 5 7
+7 37 1 5
+7 37 2 5
+7 37 3 5
+7 37 4 5
+7 37 5 5
+7 51 1 7
+7 51 2 7
+7 51 3 7
+7 51 4 7
+7 51 5 7
+7 85 1 9
+7 85 2 9
+7 85 3 9
+7 85 4 9
+7 85 5 9
+7 10 1 13
+7 10 2 13
+7 10 3 13
+7 10 4 13
+7 10 5 13
+7 23 1 5
+7 23 2 5
+7 23 3 5
+7 23 4 5
+7 23 5 5
+7 7 1 2
+7 7 2 2
+7 7 3 2
+7 7 4 2
+7 7 5 2
+7 67 1 5
+7 67 2 5
+7 67 3 5
+7 67 4 5
+7 67 5 5
+7 106 1 1
+7 106 2 1
+7 106 3 1
+7 106 4 1
+7 106 5 1
+7 88 1 5
+7 88 2 5
+7 88 3 5
+7 88 4 5
+7 88 5 5
+8 91 1 13
+8 91 2 13
+8 91 3 13
+8 91 4 13
+8 91 5 13
+8 237 1 6
+8 237 2 6
+8 237 3 6
+8 237 4 6
+8 237 5 6
+8 214 1 17
+8 214 2 17
+8 214 3 17
+8 214 4 17
+8 214 5 17
+8 65 1 1
+8 65 2 1
+8 65 3 1
+8 65 4 1
+8 65 5 1
+8 132 1 13
+8 132 2 13
+8 132 3 13
+8 132 4 13
+8 132 5 13
+8 211 1 3
+8 211 2 3
+8 211 3 3
+8 211 4 3
+8 211 5 3
+8 184 1 17
+8 184 2 17
+8 184 3 17
+8 184 4 17
+8 184 5 17
+8 171 1 6
+8 171 2 6
+8 171 3 6
+8 171 4 6
+8 171 5 6
+8 63 1 13
+8 63 2 13
+8 63 3 13
+8 63 4 13
+8 63 5 13
+8 179 1 10
+8 179 2 10
+8 179 3 10
+8 179 4 10
+8 179 5 10
+8 249 1 5
+8 249 2 5
+8 249 3 5
+8 249 4 5
+8 249 5 5
+8 102 1 6
+8 102 2 6
+8 102 3 6
+8 102 4 6
+8 102 5 6
+8 170 1 14
+8 170 2 14
+8 170 3 14
+8 170 4 14
+8 170 5 14
+8 199 1 6
+8 199 2 6
+8 199 3 6
+8 199 4 6
+8 199 5 6
+8 18 1 17
+8 18 2 17
+8 18 3 17
+8 18 4 17
+8 18 5 17
+8 147 1 4
+8 147 2 4
+8 147 3 4
+8 147 4 4
+8 147 5 4
+8 58 1 6
+8 58 2 6
+8 58 3 6
+8 58 4 6
+8 58 5 6
+8 185 1 14
+8 185 2 14
+8 185 3 14
+8 185 4 14
+8 185 5 14
+8 16 1 7
+8 16 2 7
+8 16 3 7
+8 16 4 7
+8 16 5 7
+8 9 1 5
+8 9 2 5
+8 9 3 5
+8 9 4 5
+8 9 5 5
+8 54 1 1
+8 54 2 1
+8 54 3 1
+8 54 4 1
+8 54 5 1
+8 44 1 8
+8 44 2 8
+8 44 3 8
+8 44 4 8
+8 44 5 8
+8 22 1 4
+8 22 2 4
+8 22 3 4
+8 22 4 4
+8 22 5 4
+8 212 1 17
+8 212 2 17
+8 212 3 17
+8 212 4 17
+8 212 5 17
+8 57 1 6
+8 57 2 6
+8 57 3 6
+8 57 4 6
+8 57 5 6
+8 51 1 7
+8 51 2 7
+8 51 3 7
+8 51 4 7
+8 51 5 7
+8 217 1 12
+8 217 2 12
+8 217 3 12
+8 217 4 12
+8 217 5 12
+8 176 1 2
+8 176 2 2
+8 176 3 2
+8 176 4 2
+8 176 5 2
+8 180 1 14
+8 180 2 14
+8 180 3 14
+8 180 4 14
+8 180 5 14
+8 216 1 4
+8 216 2 4
+8 216 3 4
+8 216 4 4
+8 216 5 4
+8 34 1 1
+8 34 2 1
+8 34 3 1
+8 34 4 1
+8 34 5 1
+8 146 1 5
+8 146 2 5
+8 146 3 5
+8 146 4 5
+8 146 5 5
+8 105 1 14
+8 105 2 14
+8 105 3 14
+8 105 4 14
+8 105 5 14
+8 151 1 12
+8 151 2 12
+8 151 3 12
+8 151 4 12
+8 151 5 12
+8 80 1 0
+8 80 2 0
+8 80 3 0
+8 80 4 0
+8 80 5 0
+8 32 1 5
+8 32 2 5
+8 32 3 5
+8 32 4 5
+8 32 5 5
+8 241 1 1
+8 241 2 1
+8 241 3 1
+8 241 4 1
+8 241 5 1
+8 224 1 7
+8 224 2 7
+8 224 3 7
+8 224 4 7
+8 224 5 7
+8 211 1 3
+8 211 2 3
+8 211 3 3
+8 211 4 3
+8 211 5 3
+8 52 1 13
+8 52 2 13
+8 52 3 13
+8 52 4 13
+8 52 5 13
+8 56 1 8
+8 56 2 8
+8 56 3 8
+8 56 4 8
+8 56 5 8
+8 152 1 9
+8 152 2 9
+8 152 3 9
+8 152 4 9
+8 152 5 9
+8 178 1 0
+8 178 2 0
+8 178 3 0
+8 178 4 0
+8 178 5 0
+8 93 1 12
+8 93 2 12
+8 93 3 12
+8 93 4 12
+8 93 5 12
+8 251 1 2
+8 251 2 2
+8 251 3 2
+8 251 4 2
+8 251 5 2
+8 152 1 9
+8 152 2 9
+8 152 3 9
+8 152 4 9
+8 152 5 9
+8 6 1 8
+8 6 2 8
+8 6 3 8
+8 6 4 8
+8 6 5 8
+8 93 1 12
+8 93 2 12
+8 93 3 12
+8 93 4 12
+8 93 5 12
+8 81 1 10
+8 81 2 10
+8 81 3 10
+8 81 4 10
+8 81 5 10
+8 45 1 10
+8 45 2 10
+8 45 3 10
+8 45 4 10
+8 45 5 10
+8 125 1 14
+8 125 2 14
+8 125 3 14
+8 125 4 14
+8 125 5 14
+8 172 1 4
+8 172 2 4
+8 172 3 4
+8 172 4 4
+8 172 5 4
+8 31 1 8
+8 31 2 8
+8 31 3 8
+8 31 4 8
+8 31 5 8
+8 150 1 9
+8 150 2 9
+8 150 3 9
+8 150 4 9
+8 150 5 9
+8 216 1 4
+8 216 2 4
+8 216 3 4
+8 216 4 4
+8 216 5 4
+8 243 1 15
+8 243 2 15
+8 243 3 15
+8 243 4 15
+8 243 5 15
+8 162 1 14
+8 162 2 14
+8 162 3 14
+8 162 4 14
+8 162 5 14
+8 138 1 14
+8 138 2 14
+8 138 3 14
+8 138 4 14
+8 138 5 14
+8 109 1 17
+8 109 2 17
+8 109 3 17
+8 109 4 17
+8 109 5 17
+8 146 1 5
+8 146 2 5
+8 146 3 5
+8 146 4 5
+8 146 5 5
+8 234 1 4
+8 234 2 4
+8 234 3 4
+8 234 4 4
+8 234 5 4
+8 175 1 15
+8 175 2 15
+8 175 3 15
+8 175 4 15
+8 175 5 15
+8 165 1 5
+8 165 2 5
+8 165 3 5
+8 165 4 5
+8 165 5 5
+8 28 1 7
+8 28 2 7
+8 28 3 7
+8 28 4 7
+8 28 5 7
+9 47 1 7
+9 47 2 7
+9 47 3 7
+9 47 4 7
+9 47 5 7
+9 163 1 14
+9 163 2 14
+9 163 3 14
+9 163 4 14
+9 163 5 14
+9 176 1 2
+9 176 2 2
+9 176 3 2
+9 176 4 2
+9 176 5 2
+9 59 1 1
+9 59 2 1
+9 59 3 1
+9 59 4 1
+9 59 5 1
+9 76 1 1
+9 76 2 1
+9 76 3 1
+9 76 4 1
+9 76 5 1
+9 260 1 7
+9 260 2 7
+9 260 3 7
+9 260 4 7
+9 260 5 7
+9 324 1 3
+9 324 2 3
+9 324 3 3
+9 324 4 3
+9 324 5 3
+9 160 1 13
+9 160 2 13
+9 160 3 13
+9 160 4 13
+9 160 5 13
+9 137 1 5
+9 137 2 5
+9 137 3 5
+9 137 4 5
+9 137 5 5
+9 476 1 7
+9 476 2 7
+9 476 3 7
+9 476 4 7
+9 476 5 7
+9 57 1 6
+9 57 2 6
+9 57 3 6
+9 57 4 6
+9 57 5 6
+9 204 1 1
+9 204 2 1
+9 204 3 1
+9 204 4 1
+9 204 5 1
+9 105 1 14
+9 105 2 14
+9 105 3 14
+9 105 4 14
+9 105 5 14
+9 307 1 5
+9 307 2 5
+9 307 3 5
+9 307 4 5
+9 307 5 5
+9 37 1 5
+9 37 2 5
+9 37 3 5
+9 37 4 5
+9 37 5 5
+9 297 1 9
+9 297 2 9
+9 297 3 9
+9 297 4 9
+9 297 5 9
+9 180 1 14
+9 180 2 14
+9 180 3 14
+9 180 4 14
+9 180 5 14
+9 503 1 15
+9 503 2 15
+9 503 3 15
+9 503 4 15
+9 503 5 15
+9 287 1 17
+9 287 2 17
+9 287 3 17
+9 287 4 17
+9 287 5 17
+9 325 1 1
+9 325 2 1
+9 325 3 1
+9 325 4 1
+9 325 5 1
+9 500 1 5
+9 500 2 5
+9 500 3 5
+9 500 4 5
+9 500 5 5
+9 119 1 14
+9 119 2 14
+9 119 3 14
+9 119 4 14
+9 119 5 14
+9 327 1 8
+9 327 2 8
+9 327 3 8
+9 327 4 8
+9 327 5 8
+9 83 1 3
+9 83 2 3
+9 83 3 3
+9 83 4 3
+9 83 5 3
+9 249 1 5
+9 249 2 5
+9 249 3 5
+9 249 4 5
+9 249 5 5
+9 230 1 17
+9 230 2 17
+9 230 3 17
+9 230 4 17
+9 230 5 17
+9 316 1 4
+9 316 2 4
+9 316 3 4
+9 316 4 4
+9 316 5 4
+9 424 1 0
+9 424 2 0
+9 424 3 0
+9 424 4 0
+9 424 5 0
+9 341 1 8
+9 341 2 8
+9 341 3 8
+9 341 4 8
+9 341 5 8
+9 478 1 9
+9 478 2 9
+9 478 3 9
+9 478 4 9
+9 478 5 9
+9 164 1 0
+9 164 2 0
+9 164 3 0
+9 164 4 0
+9 164 5 0
+9 319 1 12
+9 319 2 12
+9 319 3 12
+9 319 4 12
+9 319 5 12
+9 481 1 1
+9 481 2 1
+9 481 3 1
+9 481 4 1
+9 481 5 1
+9 218 1 0
+9 218 2 0
+9 218 3 0
+9 218 4 0
+9 218 5 0
+9 168 1 2
+9 168 2 2
+9 168 3 2
+9 168 4 2
+9 168 5 2
+9 54 1 1
+9 54 2 1
+9 54 3 1
+9 54 4 1
+9 54 5 1
+9 310 1 5
+9 310 2 5
+9 310 3 5
+9 310 4 5
+9 310 5 5
+9 186 1 17
+9 186 2 17
+9 186 3 17
+9 186 4 17
+9 186 5 17
+9 116 1 5
+9 116 2 5
+9 116 3 5
+9 116 4 5
+9 116 5 5
+9 335 1 7
+9 335 2 7
+9 335 3 7
+9 335 4 7
+9 335 5 7
+9 53 1 10
+9 53 2 10
+9 53 3 10
+9 53 4 10
+9 53 5 10
+9 67 1 5
+9 67 2 5
+9 67 3 5
+9 67 4 5
+9 67 5 5
+9 444 1 6
+9 444 2 6
+9 444 3 6
+9 444 4 6
+9 444 5 6
+9 368 1 12
+9 368 2 12
+9 368 3 12
+9 368 4 12
+9 368 5 12
+9 128 1 14
+9 128 2 14
+9 128 3 14
+9 128 4 14
+9 128 5 14
+9 157 1 8
+9 157 2 8
+9 157 3 8
+9 157 4 8
+9 157 5 8
+9 306 1 1
+9 306 2 1
+9 306 3 1
+9 306 4 1
+9 306 5 1
+9 35 1 7
+9 35 2 7
+9 35 3 7
+9 35 4 7
+9 35 5 7
+9 254 1 13
+9 254 2 13
+9 254 3 13
+9 254 4 13
+9 254 5 13
+9 467 1 2
+9 467 2 2
+9 467 3 2
+9 467 4 2
+9 467 5 2
+9 273 1 15
+9 273 2 15
+9 273 3 15
+9 273 4 15
+9 273 5 15
+9 23 1 5
+9 23 2 5
+9 23 3 5
+9 23 4 5
+9 23 5 5
+9 91 1 13
+9 91 2 13
+9 91 3 13
+9 91 4 13
+9 91 5 13
+9 342 1 2
+9 342 2 2
+9 342 3 2
+9 342 4 2
+9 342 5 2
+9 405 1 9
+9 405 2 9
+9 405 3 9
+9 405 4 9
+9 405 5 9
+9 413 1 4
+9 413 2 4
+9 413 3 4
+9 413 4 4
+9 413 5 4
+9 389 1 17
+9 389 2 17
+9 389 3 17
+9 389 4 17
+9 389 5 17
+9 123 1 7
+9 123 2 7
+9 123 3 7
+9 123 4 7
+9 123 5 7
+9 384 1 4
+9 384 2 4
+9 384 3 4
+9 384 4 4
+9 384 5 4
+9 299 1 5
+9 299 2 5
+9 299 3 5
+9 299 4 5
+9 299 5 5
+9 48 1 0
+9 48 2 0
+9 48 3 0
+9 48 4 0
+9 48 5 0
+9 248 1 15
+9 248 2 15
+9 248 3 15
+9 248 4 15
+9 248 5 15
+9 151 1 12
+9 151 2 12
+9 151 3 12
+9 151 4 12
+9 151 5 12
+9 477 1 12
+9 477 2 12
+9 477 3 12
+9 477 4 12
+9 477 5 12
+10 436 1 5
+10 436 2 5
+10 436 3 5
+10 436 4 5
+10 436 5 5
+10 128 1 14
+10 128 2 14
+10 128 3 14
+10 128 4 14
+10 128 5 14
+10 545 1 7
+10 545 2 7
+10 545 3 7
+10 545 4 7
+10 545 5 7
+10 332 1 1
+10 332 2 1
+10 332 3 1
+10 332 4 1
+10 332 5 1
+10 758 1 8
+10 758 2 8
+10 758 3 8
+10 758 4 8
+10 758 5 8
+10 625 1 14
+10 625 2 14
+10 625 3 14
+10 625 4 14
+10 625 5 14
+10 160 1 13
+10 160 2 13
+10 160 3 13
+10 160 4 13
+10 160 5 13
+10 194 1 6
+10 194 2 6
+10 194 3 6
+10 194 4 6
+10 194 5 6
+10 172 1 4
+10 172 2 4
+10 172 3 4
+10 172 4 4
+10 172 5 4
+10 866 1 5
+10 866 2 5
+10 866 3 5
+10 866 4 5
+10 866 5 5
+10 120 1 15
+10 120 2 15
+10 120 3 15
+10 120 4 15
+10 120 5 15
+10 923 1 3
+10 923 2 3
+10 923 3 3
+10 923 4 3
+10 923 5 3
+10 813 1 1
+10 813 2 1
+10 813 3 1
+10 813 4 1
+10 813 5 1
+10 493 1 1
+10 493 2 1
+10 493 3 1
+10 493 4 1
+10 493 5 1
+10 748 1 8
+10 748 2 8
+10 748 3 8
+10 748 4 8
+10 748 5 8
+10 104 1 1
+10 104 2 1
+10 104 3 1
+10 104 4 1
+10 104 5 1
+10 326 1 7
+10 326 2 7
+10 326 3 7
+10 326 4 7
+10 326 5 7
+10 573 1 7
+10 573 2 7
+10 573 3 7
+10 573 4 7
+10 573 5 7
+10 754 1 13
+10 754 2 13
+10 754 3 13
+10 754 4 13
+10 754 5 13
+10 146 1 5
+10 146 2 5
+10 146 3 5
+10 146 4 5
+10 146 5 5
+10 697 1 14
+10 697 2 14
+10 697 3 14
+10 697 4 14
+10 697 5 14
+10 150 1 9
+10 150 2 9
+10 150 3 9
+10 150 4 9
+10 150 5 9
+10 948 1 7
+10 948 2 7
+10 948 3 7
+10 948 4 7
+10 948 5 7
+10 726 1 14
+10 726 2 14
+10 726 3 14
+10 726 4 14
+10 726 5 14
+10 698 1 3
+10 698 2 3
+10 698 3 3
+10 698 4 3
+10 698 5 3
+10 974 1 9
+10 974 2 9
+10 974 3 9
+10 974 4 9
+10 974 5 9
+10 787 1 5
+10 787 2 5
+10 787 3 5
+10 787 4 5
+10 787 5 5
+10 449 1 5
+10 449 2 5
+10 449 3 5
+10 449 4 5
+10 449 5 5
+10 624 1 15
+10 624 2 15
+10 624 3 15
+10 624 4 15
+10 624 5 15
+10 972 1 1
+10 972 2 1
+10 972 3 1
+10 972 4 1
+10 972 5 1
+10 31 1 8
+10 31 2 8
+10 31 3 8
+10 31 4 8
+10 31 5 8
+10 568 1 17
+10 568 2 17
+10 568 3 17
+10 568 4 17
+10 568 5 17
+10 890 1 6
+10 890 2 6
+10 890 3 6
+10 890 4 6
+10 890 5 6
+10 16 1 7
+10 16 2 7
+10 16 3 7
+10 16 4 7
+10 16 5 7
+10 416 1 7
+10 416 2 7
+10 416 3 7
+10 416 4 7
+10 416 5 7
+10 499 1 5
+10 499 2 5
+10 499 3 5
+10 499 4 5
+10 499 5 5
+10 615 1 0
+10 615 2 0
+10 615 3 0
+10 615 4 0
+10 615 5 0
+10 555 1 8
+10 555 2 8
+10 555 3 8
+10 555 4 8
+10 555 5 8
+10 144 1 6
+10 144 2 6
+10 144 3 6
+10 144 4 6
+10 144 5 6
+10 509 1 17
+10 509 2 17
+10 509 3 17
+10 509 4 17
+10 509 5 17
+10 316 1 4
+10 316 2 4
+10 316 3 4
+10 316 4 4
+10 316 5 4
+10 66 1 14
+10 66 2 14
+10 66 3 14
+10 66 4 14
+10 66 5 14
+10 671 1 10
+10 671 2 10
+10 671 3 10
+10 671 4 10
+10 671 5 10
+10 310 1 5
+10 310 2 5
+10 310 3 5
+10 310 4 5
+10 310 5 5
+10 499 1 5
+10 499 2 5
+10 499 3 5
+10 499 4 5
+10 499 5 5
+10 911 1 8
+10 911 2 8
+10 911 3 8
+10 911 4 8
+10 911 5 8
+10 174 1 6
+10 174 2 6
+10 174 3 6
+10 174 4 6
+10 174 5 6
+10 721 1 5
+10 721 2 5
+10 721 3 5
+10 721 4 5
+10 721 5 5
+10 246 1 17
+10 246 2 17
+10 246 3 17
+10 246 4 17
+10 246 5 17
+10 736 1 0
+10 736 2 0
+10 736 3 0
+10 736 4 0
+10 736 5 0
+10 340 1 5
+10 340 2 5
+10 340 3 5
+10 340 4 5
+10 340 5 5
+10 214 1 17
+10 214 2 17
+10 214 3 17
+10 214 4 17
+10 214 5 17
+10 936 1 17
+10 936 2 17
+10 936 3 17
+10 936 4 17
+10 936 5 17
+10 278 1 14
+10 278 2 14
+10 278 3 14
+10 278 4 14
+10 278 5 14
+10 860 1 9
+10 860 2 9
+10 860 3 9
+10 860 4 9
+10 860 5 9
+10 673 1 3
+10 673 2 3
+10 673 3 3
+10 673 4 3
+10 673 5 3
+10 732 1 14
+10 732 2 14
+10 732 3 14
+10 732 4 14
+10 732 5 14
+10 936 1 17
+10 936 2 17
+10 936 3 17
+10 936 4 17
+10 936 5 17
+10 69 1 1
+10 69 2 1
+10 69 3 1
+10 69 4 1
+10 69 5 1
+10 865 1 14
+10 865 2 14
+10 865 3 14
+10 865 4 14
+10 865 5 14
+10 348 1 14
+10 348 2 14
+10 348 3 14
+10 348 4 14
+10 348 5 14
+10 285 1 9
+10 285 2 9
+10 285 3 9
+10 285 4 9
+10 285 5 9
+10 705 1 6
+10 705 2 6
+10 705 3 6
+10 705 4 6
+10 705 5 6
+10 154 1 13
+10 154 2 13
+10 154 3 13
+10 154 4 13
+10 154 5 13
+11 1671 1 3
+11 1671 2 3
+11 1671 3 3
+11 1671 4 3
+11 1671 5 3
+11 1334 1 1
+11 1334 2 1
+11 1334 3 1
+11 1334 4 1
+11 1334 5 1
+11 763 1 7
+11 763 2 7
+11 763 3 7
+11 763 4 7
+11 763 5 7
+11 1607 1 1
+11 1607 2 1
+11 1607 3 1
+11 1607 4 1
+11 1607 5 1
+11 1725 1 0
+11 1725 2 0
+11 1725 3 0
+11 1725 4 0
+11 1725 5 0
+11 162 1 14
+11 162 2 14
+11 162 3 14
+11 162 4 14
+11 162 5 14
+11 1068 1 4
+11 1068 2 4
+11 1068 3 4
+11 1068 4 4
+11 1068 5 4
+11 1207 1 14
+11 1207 2 14
+11 1207 3 14
+11 1207 4 14
+11 1207 5 14
+11 501 1 6
+11 501 2 6
+11 501 3 6
+11 501 4 6
+11 501 5 6
+11 1419 1 7
+11 1419 2 7
+11 1419 3 7
+11 1419 4 7
+11 1419 5 7
+11 440 1 14
+11 440 2 14
+11 440 3 14
+11 440 4 14
+11 440 5 14
+11 512 1 6
+11 512 2 6
+11 512 3 6
+11 512 4 6
+11 512 5 6
+11 1260 1 4
+11 1260 2 4
+11 1260 3 4
+11 1260 4 4
+11 1260 5 4
+11 1626 1 0
+11 1626 2 0
+11 1626 3 0
+11 1626 4 0
+11 1626 5 0
+11 1023 1 2
+11 1023 2 2
+11 1023 3 2
+11 1023 4 2
+11 1023 5 2
+11 510 1 14
+11 510 2 14
+11 510 3 14
+11 510 4 14
+11 510 5 14
+11 960 1 15
+11 960 2 15
+11 960 3 15
+11 960 4 15
+11 960 5 15
+11 1403 1 4
+11 1403 2 4
+11 1403 3 4
+11 1403 4 4
+11 1403 5 4
+11 1281 1 0
+11 1281 2 0
+11 1281 3 0
+11 1281 4 0
+11 1281 5 0
+11 1230 1 8
+11 1230 2 8
+11 1230 3 8
+11 1230 4 8
+11 1230 5 8
+11 631 1 4
+11 631 2 4
+11 631 3 4
+11 631 4 4
+11 631 5 4
+11 481 1 1
+11 481 2 1
+11 481 3 1
+11 481 4 1
+11 481 5 1
+11 229 1 12
+11 229 2 12
+11 229 3 12
+11 229 4 12
+11 229 5 12
+11 853 1 15
+11 853 2 15
+11 853 3 15
+11 853 4 15
+11 853 5 15
+11 1401 1 17
+11 1401 2 17
+11 1401 3 17
+11 1401 4 17
+11 1401 5 17
+11 896 1 4
+11 896 2 4
+11 896 3 4
+11 896 4 4
+11 896 5 4
+11 1654 1 7
+11 1654 2 7
+11 1654 3 7
+11 1654 4 7
+11 1654 5 7
+11 953 1 5
+11 953 2 5
+11 953 3 5
+11 953 4 5
+11 953 5 5
+11 530 1 6
+11 530 2 6
+11 530 3 6
+11 530 4 6
+11 530 5 6
+11 2002 1 12
+11 2002 2 12
+11 2002 3 12
+11 2002 4 12
+11 2002 5 12
+11 1953 1 2
+11 1953 2 2
+11 1953 3 2
+11 1953 4 2
+11 1953 5 2
+11 1509 1 4
+11 1509 2 4
+11 1509 3 4
+11 1509 4 4
+11 1509 5 4
+11 1778 1 10
+11 1778 2 10
+11 1778 3 10
+11 1778 4 10
+11 1778 5 10
+11 1619 1 14
+11 1619 2 14
+11 1619 3 14
+11 1619 4 14
+11 1619 5 14
+11 504 1 2
+11 504 2 2
+11 504 3 2
+11 504 4 2
+11 504 5 2
+11 9 1 5
+11 9 2 5
+11 9 3 5
+11 9 4 5
+11 9 5 5
+11 1196 1 14
+11 1196 2 14
+11 1196 3 14
+11 1196 4 14
+11 1196 5 14
+11 1285 1 12
+11 1285 2 12
+11 1285 3 12
+11 1285 4 12
+11 1285 5 12
+11 1842 1 5
+11 1842 2 5
+11 1842 3 5
+11 1842 4 5
+11 1842 5 5
+11 792 1 12
+11 792 2 12
+11 792 3 12
+11 792 4 12
+11 792 5 12
+11 1594 1 12
+11 1594 2 12
+11 1594 3 12
+11 1594 4 12
+11 1594 5 12
+11 1261 1 5
+11 1261 2 5
+11 1261 3 5
+11 1261 4 5
+11 1261 5 5
+11 1448 1 0
+11 1448 2 0
+11 1448 3 0
+11 1448 4 0
+11 1448 5 0
+11 1865 1 9
+11 1865 2 9
+11 1865 3 9
+11 1865 4 9
+11 1865 5 9
+11 375 1 4
+11 375 2 4
+11 375 3 4
+11 375 4 4
+11 375 5 4
+11 1684 1 9
+11 1684 2 9
+11 1684 3 9
+11 1684 4 9
+11 1684 5 9
+11 218 1 0
+11 218 2 0
+11 218 3 0
+11 218 4 0
+11 218 5 0
+11 151 1 12
+11 151 2 12
+11 151 3 12
+11 151 4 12
+11 151 5 12
+11 1956 1 10
+11 1956 2 10
+11 1956 3 10
+11 1956 4 10
+11 1956 5 10
+11 1670 1 9
+11 1670 2 9
+11 1670 3 9
+11 1670 4 9
+11 1670 5 9
+11 488 1 1
+11 488 2 1
+11 488 3 1
+11 488 4 1
+11 488 5 1
+11 833 1 7
+11 833 2 7
+11 833 3 7
+11 833 4 7
+11 833 5 7
+11 1508 1 6
+11 1508 2 6
+11 1508 3 6
+11 1508 4 6
+11 1508 5 6
+11 470 1 12
+11 470 2 12
+11 470 3 12
+11 470 4 12
+11 470 5 12
+11 26 1 8
+11 26 2 8
+11 26 3 8
+11 26 4 8
+11 26 5 8
+11 74 1 12
+11 74 2 12
+11 74 3 12
+11 74 4 12
+11 74 5 12
+11 1471 1 10
+11 1471 2 10
+11 1471 3 10
+11 1471 4 10
+11 1471 5 10
+11 665 1 5
+11 665 2 5
+11 665 3 5
+11 665 4 5
+11 665 5 5
+11 345 1 12
+11 345 2 12
+11 345 3 12
+11 345 4 12
+11 345 5 12
+11 506 1 5
+11 506 2 5
+11 506 3 5
+11 506 4 5
+11 506 5 5
+11 1443 1 14
+11 1443 2 14
+11 1443 3 14
+11 1443 4 14
+11 1443 5 14
+11 1126 1 10
+11 1126 2 10
+11 1126 3 10
+11 1126 4 10
+11 1126 5 10
+11 691 1 12
+11 691 2 12
+11 691 3 12
+11 691 4 12
+11 691 5 12
+11 91 1 13
+11 91 2 13
+11 91 3 13
+11 91 4 13
+11 91 5 13
+12 2730 1 8
+12 2730 2 8
+12 2730 3 8
+12 2730 4 8
+12 2730 5 8
+12 2246 1 2
+12 2246 2 2
+12 2246 3 2
+12 2246 4 2
+12 2246 5 2
+12 3903 1 12
+12 3903 2 12
+12 3903 3 12
+12 3903 4 12
+12 3903 5 12
+12 811 1 1
+12 811 2 1
+12 811 3 1
+12 811 4 1
+12 811 5 1
+12 3489 1 5
+12 3489 2 5
+12 3489 3 5
+12 3489 4 5
+12 3489 5 5
+12 918 1 6
+12 918 2 6
+12 918 3 6
+12 918 4 6
+12 918 5 6
+12 2536 1 9
+12 2536 2 9
+12 2536 3 9
+12 2536 4 9
+12 2536 5 9
+12 126 1 10
+12 126 2 10
+12 126 3 10
+12 126 4 10
+12 126 5 10
+12 102 1 6
+12 102 2 6
+12 102 3 6
+12 102 4 6
+12 102 5 6
+12 3157 1 8
+12 3157 2 8
+12 3157 3 8
+12 3157 4 8
+12 3157 5 8
+12 2042 1 14
+12 2042 2 14
+12 2042 3 14
+12 2042 4 14
+12 2042 5 14
+12 509 1 17
+12 509 2 17
+12 509 3 17
+12 509 4 17
+12 509 5 17
+12 1445 1 4
+12 1445 2 4
+12 1445 3 4
+12 1445 4 4
+12 1445 5 4
+12 1146 1 5
+12 1146 2 5
+12 1146 3 5
+12 1146 4 5
+12 1146 5 5
+12 1373 1 12
+12 1373 2 12
+12 1373 3 12
+12 1373 4 12
+12 1373 5 12
+12 1513 1 15
+12 1513 2 15
+12 1513 3 15
+12 1513 4 15
+12 1513 5 15
+12 3105 1 7
+12 3105 2 7
+12 3105 3 7
+12 3105 4 7
+12 3105 5 7
+12 2481 1 12
+12 2481 2 12
+12 2481 3 12
+12 2481 4 12
+12 2481 5 12
+12 1869 1 6
+12 1869 2 6
+12 1869 3 6
+12 1869 4 6
+12 1869 5 6
+12 1527 1 12
+12 1527 2 12
+12 1527 3 12
+12 1527 4 12
+12 1527 5 12
+12 3375 1 4
+12 3375 2 4
+12 3375 3 4
+12 3375 4 4
+12 3375 5 4
+12 2135 1 12
+12 2135 2 12
+12 2135 3 12
+12 2135 4 12
+12 2135 5 12
+12 729 1 7
+12 729 2 7
+12 729 3 7
+12 729 4 7
+12 729 5 7
+12 464 1 17
+12 464 2 17
+12 464 3 17
+12 464 4 17
+12 464 5 17
+12 2872 1 12
+12 2872 2 12
+12 2872 3 12
+12 2872 4 12
+12 2872 5 12
+12 3583 1 15
+12 3583 2 15
+12 3583 3 15
+12 3583 4 15
+12 3583 5 15
+12 869 1 2
+12 869 2 2
+12 869 3 2
+12 869 4 2
+12 869 5 2
+12 2447 1 1
+12 2447 2 1
+12 2447 3 1
+12 2447 4 1
+12 2447 5 1
+12 59 1 1
+12 59 2 1
+12 59 3 1
+12 59 4 1
+12 59 5 1
+12 3055 1 9
+12 3055 2 9
+12 3055 3 9
+12 3055 4 9
+12 3055 5 9
+12 296 1 3
+12 296 2 3
+12 296 3 3
+12 296 4 3
+12 296 5 3
+12 2118 1 10
+12 2118 2 10
+12 2118 3 10
+12 2118 4 10
+12 2118 5 10
+12 3144 1 6
+12 3144 2 6
+12 3144 3 6
+12 3144 4 6
+12 3144 5 6
+12 2467 1 8
+12 2467 2 8
+12 2467 3 8
+12 2467 4 8
+12 2467 5 8
+12 1967 1 3
+12 1967 2 3
+12 1967 3 3
+12 1967 4 3
+12 1967 5 3
+12 3705 1 8
+12 3705 2 8
+12 3705 3 8
+12 3705 4 8
+12 3705 5 8
+12 1030 1 14
+12 1030 2 14
+12 1030 3 14
+12 1030 4 14
+12 1030 5 14
+12 1865 1 9
+12 1865 2 9
+12 1865 3 9
+12 1865 4 9
+12 1865 5 9
+12 3160 1 4
+12 3160 2 4
+12 3160 3 4
+12 3160 4 4
+12 3160 5 4
+12 3232 1 12
+12 3232 2 12
+12 3232 3 12
+12 3232 4 12
+12 3232 5 12
+12 3886 1 4
+12 3886 2 4
+12 3886 3 4
+12 3886 4 4
+12 3886 5 4
+12 68 1 6
+12 68 2 6
+12 68 3 6
+12 68 4 6
+12 68 5 6
+12 1240 1 4
+12 1240 2 4
+12 1240 3 4
+12 1240 4 4
+12 1240 5 4
+12 3498 1 9
+12 3498 2 9
+12 3498 3 9
+12 3498 4 9
+12 3498 5 9
+12 1805 1 8
+12 1805 2 8
+12 1805 3 8
+12 1805 4 8
+12 1805 5 8
+12 3498 1 9
+12 3498 2 9
+12 3498 3 9
+12 3498 4 9
+12 3498 5 9
+12 3510 1 1
+12 3510 2 1
+12 3510 3 1
+12 3510 4 1
+12 3510 5 1
+12 373 1 10
+12 373 2 10
+12 373 3 10
+12 373 4 10
+12 373 5 10
+12 1286 1 15
+12 1286 2 15
+12 1286 3 15
+12 1286 4 15
+12 1286 5 15
+12 2246 1 2
+12 2246 2 2
+12 2246 3 2
+12 2246 4 2
+12 2246 5 2
+12 205 1 5
+12 205 2 5
+12 205 3 5
+12 205 4 5
+12 205 5 5
+12 1879 1 0
+12 1879 2 0
+12 1879 3 0
+12 1879 4 0
+12 1879 5 0
+12 270 1 13
+12 270 2 13
+12 270 3 13
+12 270 4 13
+12 270 5 13
+12 3478 1 8
+12 3478 2 8
+12 3478 3 8
+12 3478 4 8
+12 3478 5 8
+12 3022 1 14
+12 3022 2 14
+12 3022 3 14
+12 3022 4 14
+12 3022 5 14
+12 2200 1 0
+12 2200 2 0
+12 2200 3 0
+12 2200 4 0
+12 2200 5 0
+12 46 1 5
+12 46 2 5
+12 46 3 5
+12 46 4 5
+12 46 5 5
+12 3405 1 1
+12 3405 2 1
+12 3405 3 1
+12 3405 4 1
+12 3405 5 1
+12 1724 1 4
+12 1724 2 4
+12 1724 3 4
+12 1724 4 4
+12 1724 5 4
+12 757 1 7
+12 757 2 7
+12 757 3 7
+12 757 4 7
+12 757 5 7
+12 773 1 8
+12 773 2 8
+12 773 3 8
+12 773 4 8
+12 773 5 8
+12 211 1 3
+12 211 2 3
+12 211 3 3
+12 211 4 3
+12 211 5 3
+12 2670 1 12
+12 2670 2 12
+12 2670 3 12
+12 2670 4 12
+12 2670 5 12
+12 799 1 6
+12 799 2 6
+12 799 3 6
+12 799 4 6
+12 799 5 6
+13 893 1 6
+13 893 2 6
+13 893 3 6
+13 893 4 6
+13 893 5 6
+13 380 1 12
+13 380 2 12
+13 380 3 12
+13 380 4 12
+13 380 5 12
+13 4122 1 12
+13 4122 2 12
+13 4122 3 12
+13 4122 4 12
+13 4122 5 12
+13 5157 1 14
+13 5157 2 14
+13 5157 3 14
+13 5157 4 14
+13 5157 5 14
+13 5480 1 15
+13 5480 2 15
+13 5480 3 15
+13 5480 4 15
+13 5480 5 15
+13 5574 1 17
+13 5574 2 17
+13 5574 3 17
+13 5574 4 17
+13 5574 5 17
+13 2420 1 6
+13 2420 2 6
+13 2420 3 6
+13 2420 4 6
+13 2420 5 6
+13 7282 1 7
+13 7282 2 7
+13 7282 3 7
+13 7282 4 7
+13 7282 5 7
+13 4528 1 3
+13 4528 2 3
+13 4528 3 3
+13 4528 4 3
+13 4528 5 3
+13 637 1 6
+13 637 2 6
+13 637 3 6
+13 637 4 6
+13 637 5 6
+13 2363 1 9
+13 2363 2 9
+13 2363 3 9
+13 2363 4 9
+13 2363 5 9
+13 99 1 2
+13 99 2 2
+13 99 3 2
+13 99 4 2
+13 99 5 2
+13 1892 1 9
+13 1892 2 9
+13 1892 3 9
+13 1892 4 9
+13 1892 5 9
+13 231 1 2
+13 231 2 2
+13 231 3 2
+13 231 4 2
+13 231 5 2
+13 2672 1 15
+13 2672 2 15
+13 2672 3 15
+13 2672 4 15
+13 2672 5 15
+13 4991 1 2
+13 4991 2 2
+13 4991 3 2
+13 4991 4 2
+13 4991 5 2
+13 2715 1 15
+13 2715 2 15
+13 2715 3 15
+13 2715 4 15
+13 2715 5 15
+13 239 1 3
+13 239 2 3
+13 239 3 3
+13 239 4 3
+13 239 5 3
+13 6492 1 7
+13 6492 2 7
+13 6492 3 7
+13 6492 4 7
+13 6492 5 7
+13 1587 1 9
+13 1587 2 9
+13 1587 3 9
+13 1587 4 9
+13 1587 5 9
+13 4333 1 5
+13 4333 2 5
+13 4333 3 5
+13 4333 4 5
+13 4333 5 5
+13 6561 1 5
+13 6561 2 5
+13 6561 3 5
+13 6561 4 5
+13 6561 5 5
+13 6154 1 8
+13 6154 2 8
+13 6154 3 8
+13 6154 4 8
+13 6154 5 8
+13 7759 1 7
+13 7759 2 7
+13 7759 3 7
+13 7759 4 7
+13 7759 5 7
+13 7672 1 0
+13 7672 2 0
+13 7672 3 0
+13 7672 4 0
+13 7672 5 0
+13 2481 1 12
+13 2481 2 12
+13 2481 3 12
+13 2481 4 12
+13 2481 5 12
+13 4808 1 4
+13 4808 2 4
+13 4808 3 4
+13 4808 4 4
+13 4808 5 4
+13 8071 1 6
+13 8071 2 6
+13 8071 3 6
+13 8071 4 6
+13 8071 5 6
+13 8156 1 10
+13 8156 2 10
+13 8156 3 10
+13 8156 4 10
+13 8156 5 10
+13 2037 1 12
+13 2037 2 12
+13 2037 3 12
+13 2037 4 12
+13 2037 5 12
+13 1194 1 6
+13 1194 2 6
+13 1194 3 6
+13 1194 4 6
+13 1194 5 6
+13 1011 1 7
+13 1011 2 7
+13 1011 3 7
+13 1011 4 7
+13 1011 5 7
+13 7104 1 9
+13 7104 2 9
+13 7104 3 9
+13 7104 4 9
+13 7104 5 9
+13 999 1 13
+13 999 2 13
+13 999 3 13
+13 999 4 13
+13 999 5 13
+13 3079 1 10
+13 3079 2 10
+13 3079 3 10
+13 3079 4 10
+13 3079 5 10
+13 1167 1 15
+13 1167 2 15
+13 1167 3 15
+13 1167 4 15
+13 1167 5 15
+13 2635 1 6
+13 2635 2 6
+13 2635 3 6
+13 2635 4 6
+13 2635 5 6
+13 5668 1 0
+13 5668 2 0
+13 5668 3 0
+13 5668 4 0
+13 5668 5 0
+13 3834 1 9
+13 3834 2 9
+13 3834 3 9
+13 3834 4 9
+13 3834 5 9
+13 4540 1 10
+13 4540 2 10
+13 4540 3 10
+13 4540 4 10
+13 4540 5 10
+13 1067 1 14
+13 1067 2 14
+13 1067 3 14
+13 1067 4 14
+13 1067 5 14
+13 239 1 3
+13 239 2 3
+13 239 3 3
+13 239 4 3
+13 239 5 3
+13 4066 1 15
+13 4066 2 15
+13 4066 3 15
+13 4066 4 15
+13 4066 5 15
+13 7101 1 12
+13 7101 2 12
+13 7101 3 12
+13 7101 4 12
+13 7101 5 12
+13 7826 1 3
+13 7826 2 3
+13 7826 3 3
+13 7826 4 3
+13 7826 5 3
+13 174 1 6
+13 174 2 6
+13 174 3 6
+13 174 4 6
+13 174 5 6
+13 4578 1 14
+13 4578 2 14
+13 4578 3 14
+13 4578 4 14
+13 4578 5 14
+13 2875 1 1
+13 2875 2 1
+13 2875 3 1
+13 2875 4 1
+13 2875 5 1
+13 6067 1 10
+13 6067 2 10
+13 6067 3 10
+13 6067 4 10
+13 6067 5 10
+13 3180 1 2
+13 3180 2 2
+13 3180 3 2
+13 3180 4 2
+13 3180 5 2
+13 3426 1 6
+13 3426 2 6
+13 3426 3 6
+13 3426 4 6
+13 3426 5 6
+13 2498 1 8
+13 2498 2 8
+13 2498 3 8
+13 2498 4 8
+13 2498 5 8
+13 4938 1 6
+13 4938 2 6
+13 4938 3 6
+13 4938 4 6
+13 4938 5 6
+13 1622 1 10
+13 1622 2 10
+13 1622 3 10
+13 1622 4 10
+13 1622 5 10
+13 5260 1 9
+13 5260 2 9
+13 5260 3 9
+13 5260 4 9
+13 5260 5 9
+13 6721 1 17
+13 6721 2 17
+13 6721 3 17
+13 6721 4 17
+13 6721 5 17
+13 1809 1 3
+13 1809 2 3
+13 1809 3 3
+13 1809 4 3
+13 1809 5 3
+13 7230 1 14
+13 7230 2 14
+13 7230 3 14
+13 7230 4 14
+13 7230 5 14
+13 2000 1 8
+13 2000 2 8
+13 2000 3 8
+13 2000 4 8
+13 2000 5 8
+13 398 1 6
+13 398 2 6
+13 398 3 6
+13 398 4 6
+13 398 5 6
+13 5964 1 9
+13 5964 2 9
+13 5964 3 9
+13 5964 4 9
+13 5964 5 9
+13 6171 1 15
+13 6171 2 15
+13 6171 3 15
+13 6171 4 15
+13 6171 5 15
+13 6752 1 2
+13 6752 2 2
+13 6752 3 2
+13 6752 4 2
+13 6752 5 2
+13 7904 1 6
+13 7904 2 6
+13 7904 3 6
+13 7904 4 6
+13 7904 5 6
+14 2306 1 6
+14 2306 2 6
+14 2306 3 6
+14 2306 4 6
+14 2306 5 6
+14 1881 1 7
+14 1881 2 7
+14 1881 3 7
+14 1881 4 7
+14 1881 5 7
+14 11659 1 4
+14 11659 2 4
+14 11659 3 4
+14 11659 4 4
+14 11659 5 4
+14 12598 1 3
+14 12598 2 3
+14 12598 3 3
+14 12598 4 3
+14 12598 5 3
+14 15891 1 9
+14 15891 2 9
+14 15891 3 9
+14 15891 4 9
+14 15891 5 9
+14 7988 1 15
+14 7988 2 15
+14 7988 3 15
+14 7988 4 15
+14 7988 5 15
+14 2768 1 2
+14 2768 2 2
+14 2768 3 2
+14 2768 4 2
+14 2768 5 2
+14 2197 1 13
+14 2197 2 13
+14 2197 3 13
+14 2197 4 13
+14 2197 5 13
+14 15826 1 10
+14 15826 2 10
+14 15826 3 10
+14 15826 4 10
+14 15826 5 10
+14 4100 1 1
+14 4100 2 1
+14 4100 3 1
+14 4100 4 1
+14 4100 5 1
+14 5497 1 8
+14 5497 2 8
+14 5497 3 8
+14 5497 4 8
+14 5497 5 8
+14 1329 1 14
+14 1329 2 14
+14 1329 3 14
+14 1329 4 14
+14 1329 5 14
+14 4648 1 7
+14 4648 2 7
+14 4648 3 7
+14 4648 4 7
+14 4648 5 7
+14 11168 1 13
+14 11168 2 13
+14 11168 3 13
+14 11168 4 13
+14 11168 5 13
+14 2871 1 0
+14 2871 2 0
+14 2871 3 0
+14 2871 4 0
+14 2871 5 0
+14 6846 1 2
+14 6846 2 2
+14 6846 3 2
+14 6846 4 2
+14 6846 5 2
+14 7982 1 15
+14 7982 2 15
+14 7982 3 15
+14 7982 4 15
+14 7982 5 15
+14 2869 1 10
+14 2869 2 10
+14 2869 3 10
+14 2869 4 10
+14 2869 5 10
+14 13103 1 3
+14 13103 2 3
+14 13103 3 3
+14 13103 4 3
+14 13103 5 3
+14 9600 1 14
+14 9600 2 14
+14 9600 3 14
+14 9600 4 14
+14 9600 5 14
+14 13746 1 9
+14 13746 2 9
+14 13746 3 9
+14 13746 4 9
+14 13746 5 9
+14 9665 1 6
+14 9665 2 6
+14 9665 3 6
+14 9665 4 6
+14 9665 5 6
+14 6264 1 15
+14 6264 2 15
+14 6264 3 15
+14 6264 4 15
+14 6264 5 15
+14 10450 1 3
+14 10450 2 3
+14 10450 3 3
+14 10450 4 3
+14 10450 5 3
+14 13753 1 14
+14 13753 2 14
+14 13753 3 14
+14 13753 4 14
+14 13753 5 14
+14 13977 1 6
+14 13977 2 6
+14 13977 3 6
+14 13977 4 6
+14 13977 5 6
+14 5279 1 17
+14 5279 2 17
+14 5279 3 17
+14 5279 4 17
+14 5279 5 17
+14 7584 1 15
+14 7584 2 15
+14 7584 3 15
+14 7584 4 15
+14 7584 5 15
+14 247 1 17
+14 247 2 17
+14 247 3 17
+14 247 4 17
+14 247 5 17
+14 13284 1 7
+14 13284 2 7
+14 13284 3 7
+14 13284 4 7
+14 13284 5 7
+14 10789 1 6
+14 10789 2 6
+14 10789 3 6
+14 10789 4 6
+14 10789 5 6
+14 4332 1 3
+14 4332 2 3
+14 4332 3 3
+14 4332 4 3
+14 4332 5 3
+14 15705 1 13
+14 15705 2 13
+14 15705 3 13
+14 15705 4 13
+14 15705 5 13
+14 5405 1 8
+14 5405 2 8
+14 5405 3 8
+14 5405 4 8
+14 5405 5 8
+14 12031 1 14
+14 12031 2 14
+14 12031 3 14
+14 12031 4 14
+14 12031 5 14
+14 4684 1 15
+14 4684 2 15
+14 4684 3 15
+14 4684 4 15
+14 4684 5 15
+14 10107 1 14
+14 10107 2 14
+14 10107 3 14
+14 10107 4 14
+14 10107 5 14
+14 10645 1 4
+14 10645 2 4
+14 10645 3 4
+14 10645 4 4
+14 10645 5 4
+14 1814 1 8
+14 1814 2 8
+14 1814 3 8
+14 1814 4 8
+14 1814 5 8
+14 12906 1 0
+14 12906 2 0
+14 12906 3 0
+14 12906 4 0
+14 12906 5 0
+14 13619 1 5
+14 13619 2 5
+14 13619 3 5
+14 13619 4 5
+14 13619 5 5
+14 16110 1 3
+14 16110 2 3
+14 16110 3 3
+14 16110 4 3
+14 16110 5 3
+14 11973 1 12
+14 11973 2 12
+14 11973 3 12
+14 11973 4 12
+14 11973 5 12
+14 4483 1 13
+14 4483 2 13
+14 4483 3 13
+14 4483 4 13
+14 4483 5 13
+14 2052 1 1
+14 2052 2 1
+14 2052 3 1
+14 2052 4 1
+14 2052 5 1
+14 6049 1 7
+14 6049 2 7
+14 6049 3 7
+14 6049 4 7
+14 6049 5 7
+14 5470 1 17
+14 5470 2 17
+14 5470 3 17
+14 5470 4 17
+14 5470 5 17
+14 15849 1 4
+14 15849 2 4
+14 15849 3 4
+14 15849 4 4
+14 15849 5 4
+14 12203 1 0
+14 12203 2 0
+14 12203 3 0
+14 12203 4 0
+14 12203 5 0
+14 12665 1 12
+14 12665 2 12
+14 12665 3 12
+14 12665 4 12
+14 12665 5 12
+14 1957 1 7
+14 1957 2 7
+14 1957 3 7
+14 1957 4 7
+14 1957 5 7
+14 8833 1 17
+14 8833 2 17
+14 8833 3 17
+14 8833 4 17
+14 8833 5 17
+14 15511 1 13
+14 15511 2 13
+14 15511 3 13
+14 15511 4 13
+14 15511 5 13
+14 7190 1 6
+14 7190 2 6
+14 7190 3 6
+14 7190 4 6
+14 7190 5 6
+14 10835 1 17
+14 10835 2 17
+14 10835 3 17
+14 10835 4 17
+14 10835 5 17
+14 1350 1 2
+14 1350 2 2
+14 1350 3 2
+14 1350 4 2
+14 1350 5 2
+14 8808 1 7
+14 8808 2 7
+14 8808 3 7
+14 8808 4 7
+14 8808 5 7
+14 8043 1 13
+14 8043 2 13
+14 8043 3 13
+14 8043 4 13
+14 8043 5 13
+14 1172 1 14
+14 1172 2 14
+14 1172 3 14
+14 1172 4 14
+14 1172 5 14
+14 5572 1 17
+14 5572 2 17
+14 5572 3 17
+14 5572 4 17
+14 5572 5 17
+14 10871 1 1
+14 10871 2 1
+14 10871 3 1
+14 10871 4 1
+14 10871 5 1
+14 12865 1 6
+14 12865 2 6
+14 12865 3 6
+14 12865 4 6
+14 12865 5 6
+14 6793 1 17
+14 6793 2 17
+14 6793 3 17
+14 6793 4 17
+14 6793 5 17
+14 2973 1 5
+14 2973 2 5
+14 2973 3 5
+14 2973 4 5
+14 2973 5 5
+15 20950 1 7
+15 20950 2 7
+15 20950 3 7
+15 20950 4 7
+15 20950 5 7
+15 4112 1 6
+15 4112 2 6
+15 4112 3 6
+15 4112 4 6
+15 4112 5 6
+15 20069 1 1
+15 20069 2 1
+15 20069 3 1
+15 20069 4 1
+15 20069 5 1
+15 21040 1 17
+15 21040 2 17
+15 21040 3 17
+15 21040 4 17
+15 21040 5 17
+15 1498 1 0
+15 1498 2 0
+15 1498 3 0
+15 1498 4 0
+15 1498 5 0
+15 4453 1 3
+15 4453 2 3
+15 4453 3 3
+15 4453 4 3
+15 4453 5 3
+15 27228 1 17
+15 27228 2 17
+15 27228 3 17
+15 27228 4 17
+15 27228 5 17
+15 9353 1 2
+15 9353 2 2
+15 9353 3 2
+15 9353 4 2
+15 9353 5 2
+15 12060 1 5
+15 12060 2 5
+15 12060 3 5
+15 12060 4 5
+15 12060 5 5
+15 30253 1 15
+15 30253 2 15
+15 30253 3 15
+15 30253 4 15
+15 30253 5 15
+15 9914 1 4
+15 9914 2 4
+15 9914 3 4
+15 9914 4 4
+15 9914 5 4
+15 9111 1 17
+15 9111 2 17
+15 9111 3 17
+15 9111 4 17
+15 9111 5 17
+15 9191 1 13
+15 9191 2 13
+15 9191 3 13
+15 9191 4 13
+15 9191 5 13
+15 2061 1 15
+15 2061 2 15
+15 2061 3 15
+15 2061 4 15
+15 2061 5 15
+15 16458 1 7
+15 16458 2 7
+15 16458 3 7
+15 16458 4 7
+15 16458 5 7
+15 14420 1 17
+15 14420 2 17
+15 14420 3 17
+15 14420 4 17
+15 14420 5 17
+15 11687 1 4
+15 11687 2 4
+15 11687 3 4
+15 11687 4 4
+15 11687 5 4
+15 12915 1 14
+15 12915 2 14
+15 12915 3 14
+15 12915 4 14
+15 12915 5 14
+15 30014 1 5
+15 30014 2 5
+15 30014 3 5
+15 30014 4 5
+15 30014 5 5
+15 17852 1 8
+15 17852 2 8
+15 17852 3 8
+15 17852 4 8
+15 17852 5 8
+15 18801 1 1
+15 18801 2 1
+15 18801 3 1
+15 18801 4 1
+15 18801 5 1
+15 30476 1 10
+15 30476 2 10
+15 30476 3 10
+15 30476 4 10
+15 30476 5 10
+15 19880 1 10
+15 19880 2 10
+15 19880 3 10
+15 19880 4 10
+15 19880 5 10
+15 25937 1 13
+15 25937 2 13
+15 25937 3 13
+15 25937 4 13
+15 25937 5 13
+15 30840 1 17
+15 30840 2 17
+15 30840 3 17
+15 30840 4 17
+15 30840 5 17
+15 29260 1 4
+15 29260 2 4
+15 29260 3 4
+15 29260 4 4
+15 29260 5 4
+15 29698 1 3
+15 29698 2 3
+15 29698 3 3
+15 29698 4 3
+15 29698 5 3
+15 13207 1 12
+15 13207 2 12
+15 13207 3 12
+15 13207 4 12
+15 13207 5 12
+15 8345 1 15
+15 8345 2 15
+15 8345 3 15
+15 8345 4 15
+15 8345 5 15
+15 28649 1 0
+15 28649 2 0
+15 28649 3 0
+15 28649 4 0
+15 28649 5 0
+15 7591 1 3
+15 7591 2 3
+15 7591 3 3
+15 7591 4 3
+15 7591 5 3
+15 11417 1 4
+15 11417 2 4
+15 11417 3 4
+15 11417 4 4
+15 11417 5 4
+15 31952 1 3
+15 31952 2 3
+15 31952 3 3
+15 31952 4 3
+15 31952 5 3
+15 3936 1 5
+15 3936 2 5
+15 3936 3 5
+15 3936 4 5
+15 3936 5 5
+15 855 1 5
+15 855 2 5
+15 855 3 5
+15 855 4 5
+15 855 5 5
+15 6242 1 15
+15 6242 2 15
+15 6242 3 15
+15 6242 4 15
+15 6242 5 15
+15 7617 1 5
+15 7617 2 5
+15 7617 3 5
+15 7617 4 5
+15 7617 5 5
+15 30831 1 12
+15 30831 2 12
+15 30831 3 12
+15 30831 4 12
+15 30831 5 12
+15 27063 1 4
+15 27063 2 4
+15 27063 3 4
+15 27063 4 4
+15 27063 5 4
+15 1925 1 15
+15 1925 2 15
+15 1925 3 15
+15 1925 4 15
+15 1925 5 15
+15 31280 1 0
+15 31280 2 0
+15 31280 3 0
+15 31280 4 0
+15 31280 5 0
+15 8089 1 2
+15 8089 2 2
+15 8089 3 2
+15 8089 4 2
+15 8089 5 2
+15 14799 1 13
+15 14799 2 13
+15 14799 3 13
+15 14799 4 13
+15 14799 5 13
+15 24470 1 3
+15 24470 2 3
+15 24470 3 3
+15 24470 4 3
+15 24470 5 3
+15 3977 1 13
+15 3977 2 13
+15 3977 3 13
+15 3977 4 13
+15 3977 5 13
+15 6822 1 3
+15 6822 2 3
+15 6822 3 3
+15 6822 4 3
+15 6822 5 3
+15 10634 1 1
+15 10634 2 1
+15 10634 3 1
+15 10634 4 1
+15 10634 5 1
+15 30639 1 3
+15 30639 2 3
+15 30639 3 3
+15 30639 4 3
+15 30639 5 3
+15 4697 1 3
+15 4697 2 3
+15 4697 3 3
+15 4697 4 3
+15 4697 5 3
+15 1311 1 1
+15 1311 2 1
+15 1311 3 1
+15 1311 4 1
+15 1311 5 1
+15 29753 1 6
+15 29753 2 6
+15 29753 3 6
+15 29753 4 6
+15 29753 5 6
+15 17644 1 14
+15 17644 2 14
+15 17644 3 14
+15 17644 4 14
+15 17644 5 14
+15 11986 1 9
+15 11986 2 9
+15 11986 3 9
+15 11986 4 9
+15 11986 5 9
+15 29910 1 0
+15 29910 2 0
+15 29910 3 0
+15 29910 4 0
+15 29910 5 0
+15 8977 1 9
+15 8977 2 9
+15 8977 3 9
+15 8977 4 9
+15 8977 5 9
+15 5871 1 1
+15 5871 2 1
+15 5871 3 1
+15 5871 4 1
+15 5871 5 1
+15 22859 1 6
+15 22859 2 6
+15 22859 3 6
+15 22859 4 6
+15 22859 5 6
+15 32348 1 5
+15 32348 2 5
+15 32348 3 5
+15 32348 4 5
+15 32348 5 5
+15 26024 1 2
+15 26024 2 2
+15 26024 3 2
+15 26024 4 2
+15 26024 5 2
+15 25693 1 0
+15 25693 2 0
+15 25693 3 0
+15 25693 4 0
+15 25693 5 0
+15 11966 1 4
+15 11966 2 4
+15 11966 3 4
+15 11966 4 4
+15 11966 5 4
+15 18826 1 14
+15 18826 2 14
+15 18826 3 14
+15 18826 4 14
+15 18826 5 14
+15 31356 1 10
+15 31356 2 10
+15 31356 3 10
+15 31356 4 10
+15 31356 5 10
+15 10078 1 14
+15 10078 2 14
+15 10078 3 14
+15 10078 4 14
+15 10078 5 14
+16 58244 1 14
+16 58244 2 14
+16 58244 3 14
+16 58244 4 14
+16 58244 5 14
+16 25812 1 9
+16 25812 2 9
+16 25812 3 9
+16 25812 4 9
+16 25812 5 9
+16 5981 1 6
+16 5981 2 6
+16 5981 3 6
+16 5981 4 6
+16 5981 5 6
+16 38854 1 14
+16 38854 2 14
+16 38854 3 14
+16 38854 4 14
+16 38854 5 14
+16 29656 1 15
+16 29656 2 15
+16 29656 3 15
+16 29656 4 15
+16 29656 5 15
+16 50754 1 13
+16 50754 2 13
+16 50754 3 13
+16 50754 4 13
+16 50754 5 13
+16 5784 1 13
+16 5784 2 13
+16 5784 3 13
+16 5784 4 13
+16 5784 5 13
+16 61887 1 13
+16 61887 2 13
+16 61887 3 13
+16 61887 4 13
+16 61887 5 13
+16 48214 1 9
+16 48214 2 9
+16 48214 3 9
+16 48214 4 9
+16 48214 5 9
+16 12266 1 2
+16 12266 2 2
+16 12266 3 2
+16 12266 4 2
+16 12266 5 2
+16 38129 1 5
+16 38129 2 5
+16 38129 3 5
+16 38129 4 5
+16 38129 5 5
+16 28380 1 6
+16 28380 2 6
+16 28380 3 6
+16 28380 4 6
+16 28380 5 6
+16 50376 1 1
+16 50376 2 1
+16 50376 3 1
+16 50376 4 1
+16 50376 5 1
+16 51343 1 3
+16 51343 2 3
+16 51343 3 3
+16 51343 4 3
+16 51343 5 3
+16 10060 1 13
+16 10060 2 13
+16 10060 3 13
+16 10060 4 13
+16 10060 5 13
+16 6542 1 2
+16 6542 2 2
+16 6542 3 2
+16 6542 4 2
+16 6542 5 2
+16 9936 1 8
+16 9936 2 8
+16 9936 3 8
+16 9936 4 8
+16 9936 5 8
+16 52971 1 15
+16 52971 2 15
+16 52971 3 15
+16 52971 4 15
+16 52971 5 15
+16 48546 1 12
+16 48546 2 12
+16 48546 3 12
+16 48546 4 12
+16 48546 5 12
+16 8054 1 2
+16 8054 2 2
+16 8054 3 2
+16 8054 4 2
+16 8054 5 2
+16 62559 1 15
+16 62559 2 15
+16 62559 3 15
+16 62559 4 15
+16 62559 5 15
+16 9259 1 14
+16 9259 2 14
+16 9259 3 14
+16 9259 4 14
+16 9259 5 14
+16 29059 1 3
+16 29059 2 3
+16 29059 3 3
+16 29059 4 3
+16 29059 5 3
+16 33772 1 5
+16 33772 2 5
+16 33772 3 5
+16 33772 4 5
+16 33772 5 5
+16 60991 1 6
+16 60991 2 6
+16 60991 3 6
+16 60991 4 6
+16 60991 5 6
+16 42607 1 3
+16 42607 2 3
+16 42607 3 3
+16 42607 4 3
+16 42607 5 3
+16 42127 1 13
+16 42127 2 13
+16 42127 3 13
+16 42127 4 13
+16 42127 5 13
+16 41593 1 7
+16 41593 2 7
+16 41593 3 7
+16 41593 4 7
+16 41593 5 7
+16 2699 1 1
+16 2699 2 1
+16 2699 3 1
+16 2699 4 1
+16 2699 5 1
+16 23372 1 17
+16 23372 2 17
+16 23372 3 17
+16 23372 4 17
+16 23372 5 17
+16 28412 1 9
+16 28412 2 9
+16 28412 3 9
+16 28412 4 9
+16 28412 5 9
+16 33117 1 14
+16 33117 2 14
+16 33117 3 14
+16 33117 4 14
+16 33117 5 14
+16 19250 1 13
+16 19250 2 13
+16 19250 3 13
+16 19250 4 13
+16 19250 5 13
+16 27209 1 7
+16 27209 2 7
+16 27209 3 7
+16 27209 4 7
+16 27209 5 7
+16 24083 1 8
+16 24083 2 8
+16 24083 3 8
+16 24083 4 8
+16 24083 5 8
+16 62474 1 3
+16 62474 2 3
+16 62474 3 3
+16 62474 4 3
+16 62474 5 3
+16 58487 1 15
+16 58487 2 15
+16 58487 3 15
+16 58487 4 15
+16 58487 5 15
+16 59237 1 2
+16 59237 2 2
+16 59237 3 2
+16 59237 4 2
+16 59237 5 2
+16 33459 1 4
+16 33459 2 4
+16 33459 3 4
+16 33459 4 4
+16 33459 5 4
+16 36262 1 13
+16 36262 2 13
+16 36262 3 13
+16 36262 4 13
+16 36262 5 13
+16 45939 1 8
+16 45939 2 8
+16 45939 3 8
+16 45939 4 8
+16 45939 5 8
+16 28047 1 17
+16 28047 2 17
+16 28047 3 17
+16 28047 4 17
+16 28047 5 17
+16 53197 1 5
+16 53197 2 5
+16 53197 3 5
+16 53197 4 5
+16 53197 5 5
+16 25485 1 17
+16 25485 2 17
+16 25485 3 17
+16 25485 4 17
+16 25485 5 17
+16 1170 1 7
+16 1170 2 7
+16 1170 3 7
+16 1170 4 7
+16 1170 5 7
+16 35117 1 0
+16 35117 2 0
+16 35117 3 0
+16 35117 4 0
+16 35117 5 0
+16 51430 1 3
+16 51430 2 3
+16 51430 3 3
+16 51430 4 3
+16 51430 5 3
+16 40909 1 8
+16 40909 2 8
+16 40909 3 8
+16 40909 4 8
+16 40909 5 8
+16 43538 1 7
+16 43538 2 7
+16 43538 3 7
+16 43538 4 7
+16 43538 5 7
+16 62102 1 14
+16 62102 2 14
+16 62102 3 14
+16 62102 4 14
+16 62102 5 14
+16 32920 1 17
+16 32920 2 17
+16 32920 3 17
+16 32920 4 17
+16 32920 5 17
+16 58281 1 15
+16 58281 2 15
+16 58281 3 15
+16 58281 4 15
+16 58281 5 15
+16 25223 1 8
+16 25223 2 8
+16 25223 3 8
+16 25223 4 8
+16 25223 5 8
+16 39064 1 6
+16 39064 2 6
+16 39064 3 6
+16 39064 4 6
+16 39064 5 6
+16 59153 1 3
+16 59153 2 3
+16 59153 3 3
+16 59153 4 3
+16 59153 5 3
+16 31255 1 15
+16 31255 2 15
+16 31255 3 15
+16 31255 4 15
+16 31255 5 15
+16 36698 1 15
+16 36698 2 15
+16 36698 3 15
+16 36698 4 15
+16 36698 5 15
+16 31474 1 2
+16 31474 2 2
+16 31474 3 2
+16 31474 4 2
+16 31474 5 2
+16 26770 1 13
+16 26770 2 13
+16 26770 3 13
+16 26770 4 13
+16 26770 5 13
+16 23106 1 9
+16 23106 2 9
+16 23106 3 9
+16 23106 4 9
+16 23106 5 9
+16 15173 1 1
+16 15173 2 1
+16 15173 3 1
+16 15173 4 1
+16 15173 5 1
+16 21723 1 0
+16 21723 2 0
+16 21723 3 0
+16 21723 4 0
+16 21723 5 0
+16 56305 1 3
+16 56305 2 3
+16 56305 3 3
+16 56305 4 3
+16 56305 5 3
+16 64008 1 14
+16 64008 2 14
+16 64008 3 14
+16 64008 4 14
+16 64008 5 14
+17 93272 1 6
+17 93272 2 6
+17 93272 3 6
+17 93272 4 6
+17 93272 5 6
+17 11659 1 4
+17 11659 2 4
+17 11659 3 4
+17 11659 4 4
+17 11659 5 4
+17 96311 1 5
+17 96311 2 5
+17 96311 3 5
+17 96311 4 5
+17 96311 5 5
+17 63681 1 7
+17 63681 2 7
+17 63681 3 7
+17 63681 4 7
+17 63681 5 7
+17 80799 1 6
+17 80799 2 6
+17 80799 3 6
+17 80799 4 6
+17 80799 5 6
+17 63603 1 1
+17 63603 2 1
+17 63603 3 1
+17 63603 4 1
+17 63603 5 1
+17 112164 1 8
+17 112164 2 8
+17 112164 3 8
+17 112164 4 8
+17 112164 5 8
+17 19891 1 13
+17 19891 2 13
+17 19891 3 13
+17 19891 4 13
+17 19891 5 13
+17 44447 1 5
+17 44447 2 5
+17 44447 3 5
+17 44447 4 5
+17 44447 5 5
+17 71186 1 0
+17 71186 2 0
+17 71186 3 0
+17 71186 4 0
+17 71186 5 0
+17 91697 1 1
+17 91697 2 1
+17 91697 3 1
+17 91697 4 1
+17 91697 5 1
+17 68930 1 7
+17 68930 2 7
+17 68930 3 7
+17 68930 4 7
+17 68930 5 7
+17 22151 1 17
+17 22151 2 17
+17 22151 3 17
+17 22151 4 17
+17 22151 5 17
+17 75004 1 1
+17 75004 2 1
+17 75004 3 1
+17 75004 4 1
+17 75004 5 1
+17 89182 1 8
+17 89182 2 8
+17 89182 3 8
+17 89182 4 8
+17 89182 5 8
+17 14115 1 12
+17 14115 2 12
+17 14115 3 12
+17 14115 4 12
+17 14115 5 12
+17 13641 1 2
+17 13641 2 2
+17 13641 3 2
+17 13641 4 2
+17 13641 5 2
+17 13865 1 1
+17 13865 2 1
+17 13865 3 1
+17 13865 4 1
+17 13865 5 1
+17 81842 1 8
+17 81842 2 8
+17 81842 3 8
+17 81842 4 8
+17 81842 5 8
+17 98226 1 17
+17 98226 2 17
+17 98226 3 17
+17 98226 4 17
+17 98226 5 17
+17 51230 1 3
+17 51230 2 3
+17 51230 3 3
+17 51230 4 3
+17 51230 5 3
+17 13686 1 5
+17 13686 2 5
+17 13686 3 5
+17 13686 4 5
+17 13686 5 5
+17 91828 1 13
+17 91828 2 13
+17 91828 3 13
+17 91828 4 13
+17 91828 5 13
+17 114795 1 13
+17 114795 2 13
+17 114795 3 13
+17 114795 4 13
+17 114795 5 13
+17 12543 1 2
+17 12543 2 2
+17 12543 3 2
+17 12543 4 2
+17 12543 5 2
+17 57890 1 1
+17 57890 2 1
+17 57890 3 1
+17 57890 4 1
+17 57890 5 1
+17 115698 1 13
+17 115698 2 13
+17 115698 3 13
+17 115698 4 13
+17 115698 5 13
+17 63601 1 14
+17 63601 2 14
+17 63601 3 14
+17 63601 4 14
+17 63601 5 14
+17 92716 1 0
+17 92716 2 0
+17 92716 3 0
+17 92716 4 0
+17 92716 5 0
+17 87889 1 13
+17 87889 2 13
+17 87889 3 13
+17 87889 4 13
+17 87889 5 13
+17 123518 1 9
+17 123518 2 9
+17 123518 3 9
+17 123518 4 9
+17 123518 5 9
+17 122122 1 13
+17 122122 2 13
+17 122122 3 13
+17 122122 4 13
+17 122122 5 13
+17 101033 1 7
+17 101033 2 7
+17 101033 3 7
+17 101033 4 7
+17 101033 5 7
+17 9357 1 7
+17 9357 2 7
+17 9357 3 7
+17 9357 4 7
+17 9357 5 7
+17 127595 1 6
+17 127595 2 6
+17 127595 3 6
+17 127595 4 6
+17 127595 5 6
+17 64032 1 2
+17 64032 2 2
+17 64032 3 2
+17 64032 4 2
+17 64032 5 2
+17 72380 1 8
+17 72380 2 8
+17 72380 3 8
+17 72380 4 8
+17 72380 5 8
+17 128576 1 9
+17 128576 2 9
+17 128576 3 9
+17 128576 4 9
+17 128576 5 9
+17 58709 1 14
+17 58709 2 14
+17 58709 3 14
+17 58709 4 14
+17 58709 5 14
+17 90818 1 10
+17 90818 2 10
+17 90818 3 10
+17 90818 4 10
+17 90818 5 10
+17 96369 1 6
+17 96369 2 6
+17 96369 3 6
+17 96369 4 6
+17 96369 5 6
+17 52794 1 2
+17 52794 2 2
+17 52794 3 2
+17 52794 4 2
+17 52794 5 2
+17 105174 1 6
+17 105174 2 6
+17 105174 3 6
+17 105174 4 6
+17 105174 5 6
+17 61857 1 6
+17 61857 2 6
+17 61857 3 6
+17 61857 4 6
+17 61857 5 6
+17 19478 1 3
+17 19478 2 3
+17 19478 3 3
+17 19478 4 3
+17 19478 5 3
+17 117809 1 4
+17 117809 2 4
+17 117809 3 4
+17 117809 4 4
+17 117809 5 4
+17 72978 1 3
+17 72978 2 3
+17 72978 3 3
+17 72978 4 3
+17 72978 5 3
+17 6547 1 0
+17 6547 2 0
+17 6547 3 0
+17 6547 4 0
+17 6547 5 0
+17 68799 1 10
+17 68799 2 10
+17 68799 3 10
+17 68799 4 10
+17 68799 5 10
+17 99900 1 12
+17 99900 2 12
+17 99900 3 12
+17 99900 4 12
+17 99900 5 12
+17 126252 1 12
+17 126252 2 12
+17 126252 3 12
+17 126252 4 12
+17 126252 5 12
+17 83476 1 5
+17 83476 2 5
+17 83476 3 5
+17 83476 4 5
+17 83476 5 5
+17 38083 1 13
+17 38083 2 13
+17 38083 3 13
+17 38083 4 13
+17 38083 5 13
+17 61784 1 13
+17 61784 2 13
+17 61784 3 13
+17 61784 4 13
+17 61784 5 13
+17 24526 1 9
+17 24526 2 9
+17 24526 3 9
+17 24526 4 9
+17 24526 5 9
+17 117696 1 17
+17 117696 2 17
+17 117696 3 17
+17 117696 4 17
+17 117696 5 17
+17 50749 1 10
+17 50749 2 10
+17 50749 3 10
+17 50749 4 10
+17 50749 5 10
+17 55779 1 12
+17 55779 2 12
+17 55779 3 12
+17 55779 4 12
+17 55779 5 12
+17 2470 1 3
+17 2470 2 3
+17 2470 3 3
+17 2470 4 3
+17 2470 5 3
+17 26842 1 2
+17 26842 2 2
+17 26842 3 2
+17 26842 4 2
+17 26842 5 2
+17 16268 1 17
+17 16268 2 17
+17 16268 3 17
+17 16268 4 17
+17 16268 5 17
+17 125988 1 0
+17 125988 2 0
+17 125988 3 0
+17 125988 4 0
+17 125988 5 0
+17 15331 1 1
+17 15331 2 1
+17 15331 3 1
+17 15331 4 1
+17 15331 5 1
+17 87497 1 10
+17 87497 2 10
+17 87497 3 10
+17 87497 4 10
+17 87497 5 10
+18 250333 1 7
+18 250333 2 7
+18 250333 3 7
+18 250333 4 7
+18 250333 5 7
+18 250728 1 3
+18 250728 2 3
+18 250728 3 3
+18 250728 4 3
+18 250728 5 3
+18 218536 1 2
+18 218536 2 2
+18 218536 3 2
+18 218536 4 2
+18 218536 5 2
+18 251345 1 14
+18 251345 2 14
+18 251345 3 14
+18 251345 4 14
+18 251345 5 14
+18 123978 1 2
+18 123978 2 2
+18 123978 3 2
+18 123978 4 2
+18 123978 5 2
+18 25057 1 9
+18 25057 2 9
+18 25057 3 9
+18 25057 4 9
+18 25057 5 9
+18 55168 1 12
+18 55168 2 12
+18 55168 3 12
+18 55168 4 12
+18 55168 5 12
+18 14806 1 10
+18 14806 2 10
+18 14806 3 10
+18 14806 4 10
+18 14806 5 10
+18 252354 1 6
+18 252354 2 6
+18 252354 3 6
+18 252354 4 6
+18 252354 5 6
+18 25497 1 13
+18 25497 2 13
+18 25497 3 13
+18 25497 4 13
+18 25497 5 13
+18 62064 1 15
+18 62064 2 15
+18 62064 3 15
+18 62064 4 15
+18 62064 5 15
+18 209425 1 15
+18 209425 2 15
+18 209425 3 15
+18 209425 4 15
+18 209425 5 15
+18 41291 1 4
+18 41291 2 4
+18 41291 3 4
+18 41291 4 4
+18 41291 5 4
+18 135093 1 5
+18 135093 2 5
+18 135093 3 5
+18 135093 4 5
+18 135093 5 5
+18 245030 1 17
+18 245030 2 17
+18 245030 3 17
+18 245030 4 17
+18 245030 5 17
+18 56931 1 7
+18 56931 2 7
+18 56931 3 7
+18 56931 4 7
+18 56931 5 7
+18 2524 1 8
+18 2524 2 8
+18 2524 3 8
+18 2524 4 8
+18 2524 5 8
+18 196720 1 12
+18 196720 2 12
+18 196720 3 12
+18 196720 4 12
+18 196720 5 12
+18 244100 1 8
+18 244100 2 8
+18 244100 3 8
+18 244100 4 8
+18 244100 5 8
+18 220927 1 0
+18 220927 2 0
+18 220927 3 0
+18 220927 4 0
+18 220927 5 0
+18 216291 1 4
+18 216291 2 4
+18 216291 3 4
+18 216291 4 4
+18 216291 5 4
+18 131478 1 9
+18 131478 2 9
+18 131478 3 9
+18 131478 4 9
+18 131478 5 9
+18 34594 1 13
+18 34594 2 13
+18 34594 3 13
+18 34594 4 13
+18 34594 5 13
+18 199406 1 10
+18 199406 2 10
+18 199406 3 10
+18 199406 4 10
+18 199406 5 10
+18 26816 1 6
+18 26816 2 6
+18 26816 3 6
+18 26816 4 6
+18 26816 5 6
+18 12041 1 8
+18 12041 2 8
+18 12041 3 8
+18 12041 4 8
+18 12041 5 8
+18 91593 1 5
+18 91593 2 5
+18 91593 3 5
+18 91593 4 5
+18 91593 5 5
+18 194186 1 3
+18 194186 2 3
+18 194186 3 3
+18 194186 4 3
+18 194186 5 3
+18 150343 1 2
+18 150343 2 2
+18 150343 3 2
+18 150343 4 2
+18 150343 5 2
+18 222016 1 6
+18 222016 2 6
+18 222016 3 6
+18 222016 4 6
+18 222016 5 6
+18 100345 1 3
+18 100345 2 3
+18 100345 3 3
+18 100345 4 3
+18 100345 5 3
+18 248323 1 17
+18 248323 2 17
+18 248323 3 17
+18 248323 4 17
+18 248323 5 17
+18 248898 1 13
+18 248898 2 13
+18 248898 3 13
+18 248898 4 13
+18 248898 5 13
+18 259523 1 9
+18 259523 2 9
+18 259523 3 9
+18 259523 4 9
+18 259523 5 9
+18 13668 1 12
+18 13668 2 12
+18 13668 3 12
+18 13668 4 12
+18 13668 5 12
+18 190429 1 3
+18 190429 2 3
+18 190429 3 3
+18 190429 4 3
+18 190429 5 3
+18 227309 1 9
+18 227309 2 9
+18 227309 3 9
+18 227309 4 9
+18 227309 5 9
+18 248240 1 10
+18 248240 2 10
+18 248240 3 10
+18 248240 4 10
+18 248240 5 10
+18 179569 1 5
+18 179569 2 5
+18 179569 3 5
+18 179569 4 5
+18 179569 5 5
+18 254832 1 4
+18 254832 2 4
+18 254832 3 4
+18 254832 4 4
+18 254832 5 4
+18 141688 1 9
+18 141688 2 9
+18 141688 3 9
+18 141688 4 9
+18 141688 5 9
+18 44089 1 17
+18 44089 2 17
+18 44089 3 17
+18 44089 4 17
+18 44089 5 17
+18 145850 1 15
+18 145850 2 15
+18 145850 3 15
+18 145850 4 15
+18 145850 5 15
+18 149351 1 1
+18 149351 2 1
+18 149351 3 1
+18 149351 4 1
+18 149351 5 1
+18 161161 1 17
+18 161161 2 17
+18 161161 3 17
+18 161161 4 17
+18 161161 5 17
+18 804 1 10
+18 804 2 10
+18 804 3 10
+18 804 4 10
+18 804 5 10
+18 204942 1 0
+18 204942 2 0
+18 204942 3 0
+18 204942 4 0
+18 204942 5 0
+18 109633 1 10
+18 109633 2 10
+18 109633 3 10
+18 109633 4 10
+18 109633 5 10
+18 189623 1 1
+18 189623 2 1
+18 189623 3 1
+18 189623 4 1
+18 189623 5 1
+18 117578 1 15
+18 117578 2 15
+18 117578 3 15
+18 117578 4 15
+18 117578 5 15
+18 42863 1 13
+18 42863 2 13
+18 42863 3 13
+18 42863 4 13
+18 42863 5 13
+18 138963 1 14
+18 138963 2 14
+18 138963 3 14
+18 138963 4 14
+18 138963 5 14
+18 65040 1 1
+18 65040 2 1
+18 65040 3 1
+18 65040 4 1
+18 65040 5 1
+18 59160 1 4
+18 59160 2 4
+18 59160 3 4
+18 59160 4 4
+18 59160 5 4
+18 128405 1 5
+18 128405 2 5
+18 128405 3 5
+18 128405 4 5
+18 128405 5 5
+18 186053 1 12
+18 186053 2 12
+18 186053 3 12
+18 186053 4 12
+18 186053 5 12
+18 205204 1 2
+18 205204 2 2
+18 205204 3 2
+18 205204 4 2
+18 205204 5 2
+18 179473 1 4
+18 179473 2 4
+18 179473 3 4
+18 179473 4 4
+18 179473 5 4
+18 206442 1 2
+18 206442 2 2
+18 206442 3 2
+18 206442 4 2
+18 206442 5 2
+18 81168 1 5
+18 81168 2 5
+18 81168 3 5
+18 81168 4 5
+18 81168 5 5
+18 209591 1 3
+18 209591 2 3
+18 209591 3 3
+18 209591 4 3
+18 209591 5 3
+18 9801 1 15
+18 9801 2 15
+18 9801 3 15
+18 9801 4 15
+18 9801 5 15
+18 7180 1 17
+18 7180 2 17
+18 7180 3 17
+18 7180 4 17
+18 7180 5 17
+18 148102 1 7
+18 148102 2 7
+18 148102 3 7
+18 148102 4 7
+18 148102 5 7
+19 285360 1 12
+19 285360 2 12
+19 285360 3 12
+19 285360 4 12
+19 285360 5 12
+19 39966 1 6
+19 39966 2 6
+19 39966 3 6
+19 39966 4 6
+19 39966 5 6
+19 439938 1 15
+19 439938 2 15
+19 439938 3 15
+19 439938 4 15
+19 439938 5 15
+19 276172 1 1
+19 276172 2 1
+19 276172 3 1
+19 276172 4 1
+19 276172 5 1
+19 371729 1 17
+19 371729 2 17
+19 371729 3 17
+19 371729 4 17
+19 371729 5 17
+19 168977 1 4
+19 168977 2 4
+19 168977 3 4
+19 168977 4 4
+19 168977 5 4
+19 161548 1 14
+19 161548 2 14
+19 161548 3 14
+19 161548 4 14
+19 161548 5 14
+19 497098 1 15
+19 497098 2 15
+19 497098 3 15
+19 497098 4 15
+19 497098 5 15
+19 51980 1 4
+19 51980 2 4
+19 51980 3 4
+19 51980 4 4
+19 51980 5 4
+19 84417 1 10
+19 84417 2 10
+19 84417 3 10
+19 84417 4 10
+19 84417 5 10
+19 508848 1 3
+19 508848 2 3
+19 508848 3 3
+19 508848 4 3
+19 508848 5 3
+19 249975 1 10
+19 249975 2 10
+19 249975 3 10
+19 249975 4 10
+19 249975 5 10
+19 471817 1 0
+19 471817 2 0
+19 471817 3 0
+19 471817 4 0
+19 471817 5 0
+19 420898 1 14
+19 420898 2 14
+19 420898 3 14
+19 420898 4 14
+19 420898 5 14
+19 62009 1 6
+19 62009 2 6
+19 62009 3 6
+19 62009 4 6
+19 62009 5 6
+19 261112 1 3
+19 261112 2 3
+19 261112 3 3
+19 261112 4 3
+19 261112 5 3
+19 268374 1 7
+19 268374 2 7
+19 268374 3 7
+19 268374 4 7
+19 268374 5 7
+19 92078 1 15
+19 92078 2 15
+19 92078 3 15
+19 92078 4 15
+19 92078 5 15
+19 146323 1 13
+19 146323 2 13
+19 146323 3 13
+19 146323 4 13
+19 146323 5 13
+19 48955 1 10
+19 48955 2 10
+19 48955 3 10
+19 48955 4 10
+19 48955 5 10
+19 336033 1 0
+19 336033 2 0
+19 336033 3 0
+19 336033 4 0
+19 336033 5 0
+19 4833 1 2
+19 4833 2 2
+19 4833 3 2
+19 4833 4 2
+19 4833 5 2
+19 359506 1 3
+19 359506 2 3
+19 359506 3 3
+19 359506 4 3
+19 359506 5 3
+19 477037 1 7
+19 477037 2 7
+19 477037 3 7
+19 477037 4 7
+19 477037 5 7
+19 109440 1 0
+19 109440 2 0
+19 109440 3 0
+19 109440 4 0
+19 109440 5 0
+19 27324 1 0
+19 27324 2 0
+19 27324 3 0
+19 27324 4 0
+19 27324 5 0
+19 361772 1 15
+19 361772 2 15
+19 361772 3 15
+19 361772 4 15
+19 361772 5 15
+19 150657 1 1
+19 150657 2 1
+19 150657 3 1
+19 150657 4 1
+19 150657 5 1
+19 174825 1 8
+19 174825 2 8
+19 174825 3 8
+19 174825 4 8
+19 174825 5 8
+19 352070 1 12
+19 352070 2 12
+19 352070 3 12
+19 352070 4 12
+19 352070 5 12
+19 195450 1 13
+19 195450 2 13
+19 195450 3 13
+19 195450 4 13
+19 195450 5 13
+19 468400 1 2
+19 468400 2 2
+19 468400 3 2
+19 468400 4 2
+19 468400 5 2
+19 330682 1 10
+19 330682 2 10
+19 330682 3 10
+19 330682 4 10
+19 330682 5 10
+19 45062 1 3
+19 45062 2 3
+19 45062 3 3
+19 45062 4 3
+19 45062 5 3
+19 313788 1 1
+19 313788 2 1
+19 313788 3 1
+19 313788 4 1
+19 313788 5 1
+19 60915 1 2
+19 60915 2 2
+19 60915 3 2
+19 60915 4 2
+19 60915 5 2
+19 44594 1 17
+19 44594 2 17
+19 44594 3 17
+19 44594 4 17
+19 44594 5 17
+19 252043 1 17
+19 252043 2 17
+19 252043 3 17
+19 252043 4 17
+19 252043 5 17
+19 401426 1 17
+19 401426 2 17
+19 401426 3 17
+19 401426 4 17
+19 401426 5 17
+19 243851 1 17
+19 243851 2 17
+19 243851 3 17
+19 243851 4 17
+19 243851 5 17
+19 388726 1 4
+19 388726 2 4
+19 388726 3 4
+19 388726 4 4
+19 388726 5 4
+19 134372 1 14
+19 134372 2 14
+19 134372 3 14
+19 134372 4 14
+19 134372 5 14
+19 263363 1 17
+19 263363 2 17
+19 263363 3 17
+19 263363 4 17
+19 263363 5 17
+19 120186 1 15
+19 120186 2 15
+19 120186 3 15
+19 120186 4 15
+19 120186 5 15
+19 245005 1 6
+19 245005 2 6
+19 245005 3 6
+19 245005 4 6
+19 245005 5 6
+19 345640 1 4
+19 345640 2 4
+19 345640 3 4
+19 345640 4 4
+19 345640 5 4
+19 292026 1 1
+19 292026 2 1
+19 292026 3 1
+19 292026 4 1
+19 292026 5 1
+19 337415 1 14
+19 337415 2 14
+19 337415 3 14
+19 337415 4 14
+19 337415 5 14
+19 18276 1 2
+19 18276 2 2
+19 18276 3 2
+19 18276 4 2
+19 18276 5 2
+19 24304 1 7
+19 24304 2 7
+19 24304 3 7
+19 24304 4 7
+19 24304 5 7
+19 70660 1 1
+19 70660 2 1
+19 70660 3 1
+19 70660 4 1
+19 70660 5 1
+19 426302 1 13
+19 426302 2 13
+19 426302 3 13
+19 426302 4 13
+19 426302 5 13
+19 405580 1 15
+19 405580 2 15
+19 405580 3 15
+19 405580 4 15
+19 405580 5 15
+19 16344 1 6
+19 16344 2 6
+19 16344 3 6
+19 16344 4 6
+19 16344 5 6
+19 486995 1 7
+19 486995 2 7
+19 486995 3 7
+19 486995 4 7
+19 486995 5 7
+19 338030 1 3
+19 338030 2 3
+19 338030 3 3
+19 338030 4 3
+19 338030 5 3
+19 22647 1 17
+19 22647 2 17
+19 22647 3 17
+19 22647 4 17
+19 22647 5 17
+19 400385 1 13
+19 400385 2 13
+19 400385 3 13
+19 400385 4 13
+19 400385 5 13
+19 51070 1 8
+19 51070 2 8
+19 51070 3 8
+19 51070 4 8
+19 51070 5 8
+19 19369 1 14
+19 19369 2 14
+19 19369 3 14
+19 19369 4 14
+19 19369 5 14
+19 407294 1 17
+19 407294 2 17
+19 407294 3 17
+19 407294 4 17
+19 407294 5 17
+19 310674 1 1
+19 310674 2 1
+19 310674 3 1
+19 310674 4 1
+19 310674 5 1
+19 228351 1 6
+19 228351 2 6
+19 228351 3 6
+19 228351 4 6
+19 228351 5 6
+19 302663 1 7
+19 302663 2 7
+19 302663 3 7
+19 302663 4 7
+19 302663 5 7
+20 198355 1 15
+20 198355 2 15
+20 198355 3 15
+20 198355 4 15
+20 198355 5 15
+20 296878 1 2
+20 296878 2 2
+20 296878 3 2
+20 296878 4 2
+20 296878 5 2
+20 760518 1 8
+20 760518 2 8
+20 760518 3 8
+20 760518 4 8
+20 760518 5 8
+20 924592 1 1
+20 924592 2 1
+20 924592 3 1
+20 924592 4 1
+20 924592 5 1
+20 561909 1 14
+20 561909 2 14
+20 561909 3 14
+20 561909 4 14
+20 561909 5 14
+20 364293 1 9
+20 364293 2 9
+20 364293 3 9
+20 364293 4 9
+20 364293 5 9
+20 431304 1 15
+20 431304 2 15
+20 431304 3 15
+20 431304 4 15
+20 431304 5 15
+20 24977 1 2
+20 24977 2 2
+20 24977 3 2
+20 24977 4 2
+20 24977 5 2
+20 98684 1 12
+20 98684 2 12
+20 98684 3 12
+20 98684 4 12
+20 98684 5 12
+20 116875 1 6
+20 116875 2 6
+20 116875 3 6
+20 116875 4 6
+20 116875 5 6
+20 121330 1 14
+20 121330 2 14
+20 121330 3 14
+20 121330 4 14
+20 121330 5 14
+20 977011 1 7
+20 977011 2 7
+20 977011 3 7
+20 977011 4 7
+20 977011 5 7
+20 789443 1 2
+20 789443 2 2
+20 789443 3 2
+20 789443 4 2
+20 789443 5 2
+20 539203 1 5
+20 539203 2 5
+20 539203 3 5
+20 539203 4 5
+20 539203 5 5
+20 981911 1 15
+20 981911 2 15
+20 981911 3 15
+20 981911 4 15
+20 981911 5 15
+20 495588 1 1
+20 495588 2 1
+20 495588 3 1
+20 495588 4 1
+20 495588 5 1
+20 24759 1 2
+20 24759 2 2
+20 24759 3 2
+20 24759 4 2
+20 24759 5 2
+20 355299 1 13
+20 355299 2 13
+20 355299 3 13
+20 355299 4 13
+20 355299 5 13
+20 706015 1 0
+20 706015 2 0
+20 706015 3 0
+20 706015 4 0
+20 706015 5 0
+20 1024100 1 13
+20 1024100 2 13
+20 1024100 3 13
+20 1024100 4 13
+20 1024100 5 13
+20 672600 1 7
+20 672600 2 7
+20 672600 3 7
+20 672600 4 7
+20 672600 5 7
+20 420182 1 8
+20 420182 2 8
+20 420182 3 8
+20 420182 4 8
+20 420182 5 8
+20 149062 1 1
+20 149062 2 1
+20 149062 3 1
+20 149062 4 1
+20 149062 5 1
+20 292328 1 7
+20 292328 2 7
+20 292328 3 7
+20 292328 4 7
+20 292328 5 7
+20 522558 1 2
+20 522558 2 2
+20 522558 3 2
+20 522558 4 2
+20 522558 5 2
+20 628026 1 9
+20 628026 2 9
+20 628026 3 9
+20 628026 4 9
+20 628026 5 9
+20 139803 1 0
+20 139803 2 0
+20 139803 3 0
+20 139803 4 0
+20 139803 5 0
+20 457303 1 1
+20 457303 2 1
+20 457303 3 1
+20 457303 4 1
+20 457303 5 1
+20 559378 1 12
+20 559378 2 12
+20 559378 3 12
+20 559378 4 12
+20 559378 5 12
+20 478051 1 1
+20 478051 2 1
+20 478051 3 1
+20 478051 4 1
+20 478051 5 1
+20 670978 1 5
+20 670978 2 5
+20 670978 3 5
+20 670978 4 5
+20 670978 5 5
+20 782352 1 14
+20 782352 2 14
+20 782352 3 14
+20 782352 4 14
+20 782352 5 14
+20 215312 1 15
+20 215312 2 15
+20 215312 3 15
+20 215312 4 15
+20 215312 5 15
+20 807766 1 13
+20 807766 2 13
+20 807766 3 13
+20 807766 4 13
+20 807766 5 13
+20 1027955 1 17
+20 1027955 2 17
+20 1027955 3 17
+20 1027955 4 17
+20 1027955 5 17
+20 724067 1 1
+20 724067 2 1
+20 724067 3 1
+20 724067 4 1
+20 724067 5 1
+20 179596 1 3
+20 179596 2 3
+20 179596 3 3
+20 179596 4 3
+20 179596 5 3
+20 8911 1 13
+20 8911 2 13
+20 8911 3 13
+20 8911 4 13
+20 8911 5 13
+20 462137 1 1
+20 462137 2 1
+20 462137 3 1
+20 462137 4 1
+20 462137 5 1
+20 451091 1 2
+20 451091 2 2
+20 451091 3 2
+20 451091 4 2
+20 451091 5 2
+20 837481 1 4
+20 837481 2 4
+20 837481 3 4
+20 837481 4 4
+20 837481 5 4
+20 61499 1 12
+20 61499 2 12
+20 61499 3 12
+20 61499 4 12
+20 61499 5 12
+20 64499 1 1
+20 64499 2 1
+20 64499 3 1
+20 64499 4 1
+20 64499 5 1
+20 498651 1 14
+20 498651 2 14
+20 498651 3 14
+20 498651 4 14
+20 498651 5 14
+20 139939 1 7
+20 139939 2 7
+20 139939 3 7
+20 139939 4 7
+20 139939 5 7
+20 1021247 1 13
+20 1021247 2 13
+20 1021247 3 13
+20 1021247 4 13
+20 1021247 5 13
+20 203158 1 4
+20 203158 2 4
+20 203158 3 4
+20 203158 4 4
+20 203158 5 4
+20 165605 1 5
+20 165605 2 5
+20 165605 3 5
+20 165605 4 5
+20 165605 5 5
+20 996551 1 10
+20 996551 2 10
+20 996551 3 10
+20 996551 4 10
+20 996551 5 10
+20 344367 1 1
+20 344367 2 1
+20 344367 3 1
+20 344367 4 1
+20 344367 5 1
+20 471785 1 7
+20 471785 2 7
+20 471785 3 7
+20 471785 4 7
+20 471785 5 7
+20 552276 1 8
+20 552276 2 8
+20 552276 3 8
+20 552276 4 8
+20 552276 5 8
+20 535414 1 7
+20 535414 2 7
+20 535414 3 7
+20 535414 4 7
+20 535414 5 7
+20 850839 1 17
+20 850839 2 17
+20 850839 3 17
+20 850839 4 17
+20 850839 5 17
+20 707079 1 2
+20 707079 2 2
+20 707079 3 2
+20 707079 4 2
+20 707079 5 2
+20 311484 1 2
+20 311484 2 2
+20 311484 3 2
+20 311484 4 2
+20 311484 5 2
+20 682726 1 15
+20 682726 2 15
+20 682726 3 15
+20 682726 4 15
+20 682726 5 15
+20 718518 1 7
+20 718518 2 7
+20 718518 3 7
+20 718518 4 7
+20 718518 5 7
+20 584929 1 15
+20 584929 2 15
+20 584929 3 15
+20 584929 4 15
+20 584929 5 15
+20 496804 1 12
+20 496804 2 12
+20 496804 3 12
+20 496804 4 12
+20 496804 5 12
+20 871520 1 3
+20 871520 2 3
+20 871520 3 3
+20 871520 4 3
+20 871520 5 3
+20 766462 1 3
+20 766462 2 3
+20 766462 3 3
+20 766462 4 3
+20 766462 5 3
+20 547770 1 10
+20 547770 2 10
+20 547770 3 10
+20 547770 4 10
+20 547770 5 10
+20 289035 1 17
+20 289035 2 17
+20 289035 3 17
+20 289035 4 17
+20 289035 5 17
+21 1544102 1 17
+21 1544102 2 17
+21 1544102 3 17
+21 1544102 4 17
+21 1544102 5 17
+21 1921124 1 4
+21 1921124 2 4
+21 1921124 3 4
+21 1921124 4 4
+21 1921124 5 4
+21 1244065 1 6
+21 1244065 2 6
+21 1244065 3 6
+21 1244065 4 6
+21 1244065 5 6
+21 949419 1 15
+21 949419 2 15
+21 949419 3 15
+21 949419 4 15
+21 949419 5 15
+21 809660 1 5
+21 809660 2 5
+21 809660 3 5
+21 809660 4 5
+21 809660 5 5
+21 2081078 1 10
+21 2081078 2 10
+21 2081078 3 10
+21 2081078 4 10
+21 2081078 5 10
+21 1324116 1 15
+21 1324116 2 15
+21 1324116 3 15
+21 1324116 4 15
+21 1324116 5 15
+21 769413 1 8
+21 769413 2 8
+21 769413 3 8
+21 769413 4 8
+21 769413 5 8
+21 1471174 1 1
+21 1471174 2 1
+21 1471174 3 1
+21 1471174 4 1
+21 1471174 5 1
+21 2010804 1 7
+21 2010804 2 7
+21 2010804 3 7
+21 2010804 4 7
+21 2010804 5 7
+21 1616690 1 14
+21 1616690 2 14
+21 1616690 3 14
+21 1616690 4 14
+21 1616690 5 14
+21 1017561 1 9
+21 1017561 2 9
+21 1017561 3 9
+21 1017561 4 9
+21 1017561 5 9
+21 957826 1 0
+21 957826 2 0
+21 957826 3 0
+21 957826 4 0
+21 957826 5 0
+21 562864 1 6
+21 562864 2 6
+21 562864 3 6
+21 562864 4 6
+21 562864 5 6
+21 536746 1 4
+21 536746 2 4
+21 536746 3 4
+21 536746 4 4
+21 536746 5 4
+21 2010490 1 17
+21 2010490 2 17
+21 2010490 3 17
+21 2010490 4 17
+21 2010490 5 17
+21 814896 1 6
+21 814896 2 6
+21 814896 3 6
+21 814896 4 6
+21 814896 5 6
+21 2085665 1 5
+21 2085665 2 5
+21 2085665 3 5
+21 2085665 4 5
+21 2085665 5 5
+21 608239 1 12
+21 608239 2 12
+21 608239 3 12
+21 608239 4 12
+21 608239 5 12
+21 1114271 1 6
+21 1114271 2 6
+21 1114271 3 6
+21 1114271 4 6
+21 1114271 5 6
+21 1578775 1 5
+21 1578775 2 5
+21 1578775 3 5
+21 1578775 4 5
+21 1578775 5 5
+21 293537 1 2
+21 293537 2 2
+21 293537 3 2
+21 293537 4 2
+21 293537 5 2
+21 1260407 1 8
+21 1260407 2 8
+21 1260407 3 8
+21 1260407 4 8
+21 1260407 5 8
+21 569959 1 4
+21 569959 2 4
+21 569959 3 4
+21 569959 4 4
+21 569959 5 4
+21 1653758 1 9
+21 1653758 2 9
+21 1653758 3 9
+21 1653758 4 9
+21 1653758 5 9
+21 643309 1 0
+21 643309 2 0
+21 643309 3 0
+21 643309 4 0
+21 643309 5 0
+21 1982846 1 3
+21 1982846 2 3
+21 1982846 3 3
+21 1982846 4 3
+21 1982846 5 3
+21 1986639 1 17
+21 1986639 2 17
+21 1986639 3 17
+21 1986639 4 17
+21 1986639 5 17
+21 1370291 1 17
+21 1370291 2 17
+21 1370291 3 17
+21 1370291 4 17
+21 1370291 5 17
+21 1656681 1 8
+21 1656681 2 8
+21 1656681 3 8
+21 1656681 4 8
+21 1656681 5 8
+21 241796 1 4
+21 241796 2 4
+21 241796 3 4
+21 241796 4 4
+21 241796 5 4
+21 215997 1 6
+21 215997 2 6
+21 215997 3 6
+21 215997 4 6
+21 215997 5 6
+21 821384 1 17
+21 821384 2 17
+21 821384 3 17
+21 821384 4 17
+21 821384 5 17
+21 331161 1 1
+21 331161 2 1
+21 331161 3 1
+21 331161 4 1
+21 331161 5 1
+21 17355 1 5
+21 17355 2 5
+21 17355 3 5
+21 17355 4 5
+21 17355 5 5
+21 1905273 1 7
+21 1905273 2 7
+21 1905273 3 7
+21 1905273 4 7
+21 1905273 5 7
+21 1045457 1 10
+21 1045457 2 10
+21 1045457 3 10
+21 1045457 4 10
+21 1045457 5 10
+21 799145 1 9
+21 799145 2 9
+21 799145 3 9
+21 799145 4 9
+21 799145 5 9
+21 683994 1 13
+21 683994 2 13
+21 683994 3 13
+21 683994 4 13
+21 683994 5 13
+21 1750830 1 4
+21 1750830 2 4
+21 1750830 3 4
+21 1750830 4 4
+21 1750830 5 4
+21 1346663 1 13
+21 1346663 2 13
+21 1346663 3 13
+21 1346663 4 13
+21 1346663 5 13
+21 1200358 1 6
+21 1200358 2 6
+21 1200358 3 6
+21 1200358 4 6
+21 1200358 5 6
+21 968444 1 4
+21 968444 2 4
+21 968444 3 4
+21 968444 4 4
+21 968444 5 4
+21 469486 1 15
+21 469486 2 15
+21 469486 3 15
+21 469486 4 15
+21 469486 5 15
+21 223784 1 3
+21 223784 2 3
+21 223784 3 3
+21 223784 4 3
+21 223784 5 3
+21 841795 1 4
+21 841795 2 4
+21 841795 3 4
+21 841795 4 4
+21 841795 5 4
+21 290242 1 2
+21 290242 2 2
+21 290242 3 2
+21 290242 4 2
+21 290242 5 2
+21 1704107 1 2
+21 1704107 2 2
+21 1704107 3 2
+21 1704107 4 2
+21 1704107 5 2
+21 1087348 1 9
+21 1087348 2 9
+21 1087348 3 9
+21 1087348 4 9
+21 1087348 5 9
+21 513237 1 2
+21 513237 2 2
+21 513237 3 2
+21 513237 4 2
+21 513237 5 2
+21 761725 1 13
+21 761725 2 13
+21 761725 3 13
+21 761725 4 13
+21 761725 5 13
+21 577471 1 6
+21 577471 2 6
+21 577471 3 6
+21 577471 4 6
+21 577471 5 6
+21 875954 1 9
+21 875954 2 9
+21 875954 3 9
+21 875954 4 9
+21 875954 5 9
+21 283735 1 8
+21 283735 2 8
+21 283735 3 8
+21 283735 4 8
+21 283735 5 8
+21 541381 1 17
+21 541381 2 17
+21 541381 3 17
+21 541381 4 17
+21 541381 5 17
+21 1774181 1 14
+21 1774181 2 14
+21 1774181 3 14
+21 1774181 4 14
+21 1774181 5 14
+21 500169 1 17
+21 500169 2 17
+21 500169 3 17
+21 500169 4 17
+21 500169 5 17
+21 1201575 1 7
+21 1201575 2 7
+21 1201575 3 7
+21 1201575 4 7
+21 1201575 5 7
+21 691701 1 1
+21 691701 2 1
+21 691701 3 1
+21 691701 4 1
+21 691701 5 1
+21 172861 1 4
+21 172861 2 4
+21 172861 3 4
+21 172861 4 4
+21 172861 5 4
+21 544935 1 0
+21 544935 2 0
+21 544935 3 0
+21 544935 4 0
+21 544935 5 0
+21 543047 1 3
+21 543047 2 3
+21 543047 3 3
+21 543047 4 3
+21 543047 5 3
+21 1555372 1 3
+21 1555372 2 3
+21 1555372 3 3
+21 1555372 4 3
+21 1555372 5 3
+21 1754316 1 8
+21 1754316 2 8
+21 1754316 3 8
+21 1754316 4 8
+21 1754316 5 8
+22 1701163 1 15
+22 1701163 2 15
+22 1701163 3 15
+22 1701163 4 15
+22 1701163 5 15
+22 2291265 1 9
+22 2291265 2 9
+22 2291265 3 9
+22 2291265 4 9
+22 2291265 5 9
+22 2939154 1 17
+22 2939154 2 17
+22 2939154 3 17
+22 2939154 4 17
+22 2939154 5 17
+22 874939 1 9
+22 874939 2 9
+22 874939 3 9
+22 874939 4 9
+22 874939 5 9
+22 66406 1 0
+22 66406 2 0
+22 66406 3 0
+22 66406 4 0
+22 66406 5 0
+22 2173604 1 10
+22 2173604 2 10
+22 2173604 3 10
+22 2173604 4 10
+22 2173604 5 10
+22 3888560 1 9
+22 3888560 2 9
+22 3888560 3 9
+22 3888560 4 9
+22 3888560 5 9
+22 633256 1 9
+22 633256 2 9
+22 633256 3 9
+22 633256 4 9
+22 633256 5 9
+22 499433 1 0
+22 499433 2 0
+22 499433 3 0
+22 499433 4 0
+22 499433 5 0
+22 523322 1 9
+22 523322 2 9
+22 523322 3 9
+22 523322 4 9
+22 523322 5 9
+22 3422065 1 9
+22 3422065 2 9
+22 3422065 3 9
+22 3422065 4 9
+22 3422065 5 9
+22 1944488 1 13
+22 1944488 2 13
+22 1944488 3 13
+22 1944488 4 13
+22 1944488 5 13
+22 1501254 1 6
+22 1501254 2 6
+22 1501254 3 6
+22 1501254 4 6
+22 1501254 5 6
+22 3637609 1 9
+22 3637609 2 9
+22 3637609 3 9
+22 3637609 4 9
+22 3637609 5 9
+22 3969393 1 3
+22 3969393 2 3
+22 3969393 3 3
+22 3969393 4 3
+22 3969393 5 3
+22 3757241 1 9
+22 3757241 2 9
+22 3757241 3 9
+22 3757241 4 9
+22 3757241 5 9
+22 541635 1 2
+22 541635 2 2
+22 541635 3 2
+22 541635 4 2
+22 541635 5 2
+22 40295 1 1
+22 40295 2 1
+22 40295 3 1
+22 40295 4 1
+22 40295 5 1
+22 4047297 1 0
+22 4047297 2 0
+22 4047297 3 0
+22 4047297 4 0
+22 4047297 5 0
+22 3989485 1 8
+22 3989485 2 8
+22 3989485 3 8
+22 3989485 4 8
+22 3989485 5 8
+22 4103132 1 10
+22 4103132 2 10
+22 4103132 3 10
+22 4103132 4 10
+22 4103132 5 10
+22 1722049 1 5
+22 1722049 2 5
+22 1722049 3 5
+22 1722049 4 5
+22 1722049 5 5
+22 23525 1 9
+22 23525 2 9
+22 23525 3 9
+22 23525 4 9
+22 23525 5 9
+22 2882794 1 13
+22 2882794 2 13
+22 2882794 3 13
+22 2882794 4 13
+22 2882794 5 13
+22 3503039 1 15
+22 3503039 2 15
+22 3503039 3 15
+22 3503039 4 15
+22 3503039 5 15
+22 597461 1 7
+22 597461 2 7
+22 597461 3 7
+22 597461 4 7
+22 597461 5 7
+22 648021 1 14
+22 648021 2 14
+22 648021 3 14
+22 648021 4 14
+22 648021 5 14
+22 2641512 1 2
+22 2641512 2 2
+22 2641512 3 2
+22 2641512 4 2
+22 2641512 5 2
+22 3131854 1 0
+22 3131854 2 0
+22 3131854 3 0
+22 3131854 4 0
+22 3131854 5 0
+22 3363671 1 9
+22 3363671 2 9
+22 3363671 3 9
+22 3363671 4 9
+22 3363671 5 9
+22 480767 1 0
+22 480767 2 0
+22 480767 3 0
+22 480767 4 0
+22 480767 5 0
+22 866487 1 8
+22 866487 2 8
+22 866487 3 8
+22 866487 4 8
+22 866487 5 8
+22 3197473 1 1
+22 3197473 2 1
+22 3197473 3 1
+22 3197473 4 1
+22 3197473 5 1
+22 1760976 1 2
+22 1760976 2 2
+22 1760976 3 2
+22 1760976 4 2
+22 1760976 5 2
+22 952003 1 4
+22 952003 2 4
+22 952003 3 4
+22 952003 4 4
+22 952003 5 4
+22 458806 1 17
+22 458806 2 17
+22 458806 3 17
+22 458806 4 17
+22 458806 5 17
+22 2642177 1 15
+22 2642177 2 15
+22 2642177 3 15
+22 2642177 4 15
+22 2642177 5 15
+22 3671322 1 10
+22 3671322 2 10
+22 3671322 3 10
+22 3671322 4 10
+22 3671322 5 10
+22 18422 1 12
+22 18422 2 12
+22 18422 3 12
+22 18422 4 12
+22 18422 5 12
+22 4143069 1 0
+22 4143069 2 0
+22 4143069 3 0
+22 4143069 4 0
+22 4143069 5 0
+22 4013422 1 13
+22 4013422 2 13
+22 4013422 3 13
+22 4013422 4 13
+22 4013422 5 13
+22 3026661 1 13
+22 3026661 2 13
+22 3026661 3 13
+22 3026661 4 13
+22 3026661 5 13
+22 1402336 1 5
+22 1402336 2 5
+22 1402336 3 5
+22 1402336 4 5
+22 1402336 5 5
+22 3702708 1 10
+22 3702708 2 10
+22 3702708 3 10
+22 3702708 4 10
+22 3702708 5 10
+22 2069402 1 8
+22 2069402 2 8
+22 2069402 3 8
+22 2069402 4 8
+22 2069402 5 8
+22 1380150 1 15
+22 1380150 2 15
+22 1380150 3 15
+22 1380150 4 15
+22 1380150 5 15
+22 2126142 1 12
+22 2126142 2 12
+22 2126142 3 12
+22 2126142 4 12
+22 2126142 5 12
+22 3380057 1 0
+22 3380057 2 0
+22 3380057 3 0
+22 3380057 4 0
+22 3380057 5 0
+22 814956 1 9
+22 814956 2 9
+22 814956 3 9
+22 814956 4 9
+22 814956 5 9
+22 1055203 1 1
+22 1055203 2 1
+22 1055203 3 1
+22 1055203 4 1
+22 1055203 5 1
+22 940480 1 12
+22 940480 2 12
+22 940480 3 12
+22 940480 4 12
+22 940480 5 12
+22 3647615 1 17
+22 3647615 2 17
+22 3647615 3 17
+22 3647615 4 17
+22 3647615 5 17
+22 3000063 1 6
+22 3000063 2 6
+22 3000063 3 6
+22 3000063 4 6
+22 3000063 5 6
+22 3033624 1 13
+22 3033624 2 13
+22 3033624 3 13
+22 3033624 4 13
+22 3033624 5 13
+22 3135628 1 9
+22 3135628 2 9
+22 3135628 3 9
+22 3135628 4 9
+22 3135628 5 9
+22 1580393 1 1
+22 1580393 2 1
+22 1580393 3 1
+22 1580393 4 1
+22 1580393 5 1
+22 4193568 1 8
+22 4193568 2 8
+22 4193568 3 8
+22 4193568 4 8
+22 4193568 5 8
+22 800980 1 10
+22 800980 2 10
+22 800980 3 10
+22 800980 4 10
+22 800980 5 10
+22 1419961 1 17
+22 1419961 2 17
+22 1419961 3 17
+22 1419961 4 17
+22 1419961 5 17
+22 1144691 1 3
+22 1144691 2 3
+22 1144691 3 3
+22 1144691 4 3
+22 1144691 5 3
+22 2573267 1 8
+22 2573267 2 8
+22 2573267 3 8
+22 2573267 4 8
+22 2573267 5 8
+22 3310445 1 7
+22 3310445 2 7
+22 3310445 3 7
+22 3310445 4 7
+22 3310445 5 7
+22 629717 1 13
+22 629717 2 13
+22 629717 3 13
+22 629717 4 13
+22 629717 5 13
+22 1552778 1 17
+22 1552778 2 17
+22 1552778 3 17
+22 1552778 4 17
+22 1552778 5 17
+23 3046911 1 1
+23 3046911 2 1
+23 3046911 3 1
+23 3046911 4 1
+23 3046911 5 1
+23 769783 1 9
+23 769783 2 9
+23 769783 3 9
+23 769783 4 9
+23 769783 5 9
+23 2374124 1 13
+23 2374124 2 13
+23 2374124 3 13
+23 2374124 4 13
+23 2374124 5 13
+23 2996918 1 15
+23 2996918 2 15
+23 2996918 3 15
+23 2996918 4 15
+23 2996918 5 15
+23 2411310 1 6
+23 2411310 2 6
+23 2411310 3 6
+23 2411310 4 6
+23 2411310 5 6
+23 744660 1 8
+23 744660 2 8
+23 744660 3 8
+23 744660 4 8
+23 744660 5 8
+23 7927100 1 17
+23 7927100 2 17
+23 7927100 3 17
+23 7927100 4 17
+23 7927100 5 17
+23 1377692 1 0
+23 1377692 2 0
+23 1377692 3 0
+23 1377692 4 0
+23 1377692 5 0
+23 2920499 1 4
+23 2920499 2 4
+23 2920499 3 4
+23 2920499 4 4
+23 2920499 5 4
+23 6611555 1 4
+23 6611555 2 4
+23 6611555 3 4
+23 6611555 4 4
+23 6611555 5 4
+23 723122 1 0
+23 723122 2 0
+23 723122 3 0
+23 723122 4 0
+23 723122 5 0
+23 5130765 1 14
+23 5130765 2 14
+23 5130765 3 14
+23 5130765 4 14
+23 5130765 5 14
+23 621060 1 6
+23 621060 2 6
+23 621060 3 6
+23 621060 4 6
+23 621060 5 6
+23 6806998 1 1
+23 6806998 2 1
+23 6806998 3 1
+23 6806998 4 1
+23 6806998 5 1
+23 3524228 1 7
+23 3524228 2 7
+23 3524228 3 7
+23 3524228 4 7
+23 3524228 5 7
+23 1077839 1 1
+23 1077839 2 1
+23 1077839 3 1
+23 1077839 4 1
+23 1077839 5 1
+23 5526077 1 8
+23 5526077 2 8
+23 5526077 3 8
+23 5526077 4 8
+23 5526077 5 8
+23 7013541 1 13
+23 7013541 2 13
+23 7013541 3 13
+23 7013541 4 13
+23 7013541 5 13
+23 4998096 1 9
+23 4998096 2 9
+23 4998096 3 9
+23 4998096 4 9
+23 4998096 5 9
+23 5128233 1 5
+23 5128233 2 5
+23 5128233 3 5
+23 5128233 4 5
+23 5128233 5 5
+23 1863578 1 9
+23 1863578 2 9
+23 1863578 3 9
+23 1863578 4 9
+23 1863578 5 9
+23 6838283 1 17
+23 6838283 2 17
+23 6838283 3 17
+23 6838283 4 17
+23 6838283 5 17
+23 1134869 1 1
+23 1134869 2 1
+23 1134869 3 1
+23 1134869 4 1
+23 1134869 5 1
+23 2111849 1 12
+23 2111849 2 12
+23 2111849 3 12
+23 2111849 4 12
+23 2111849 5 12
+23 1488511 1 9
+23 1488511 2 9
+23 1488511 3 9
+23 1488511 4 9
+23 1488511 5 9
+23 4807048 1 10
+23 4807048 2 10
+23 4807048 3 10
+23 4807048 4 10
+23 4807048 5 10
+23 393912 1 13
+23 393912 2 13
+23 393912 3 13
+23 393912 4 13
+23 393912 5 13
+23 5219424 1 0
+23 5219424 2 0
+23 5219424 3 0
+23 5219424 4 0
+23 5219424 5 0
+23 8137072 1 2
+23 8137072 2 2
+23 8137072 3 2
+23 8137072 4 2
+23 8137072 5 2
+23 5590877 1 1
+23 5590877 2 1
+23 5590877 3 1
+23 5590877 4 1
+23 5590877 5 1
+23 5294465 1 2
+23 5294465 2 2
+23 5294465 3 2
+23 5294465 4 2
+23 5294465 5 2
+23 1348707 1 6
+23 1348707 2 6
+23 1348707 3 6
+23 1348707 4 6
+23 1348707 5 6
+23 7997848 1 6
+23 7997848 2 6
+23 7997848 3 6
+23 7997848 4 6
+23 7997848 5 6
+23 7575827 1 10
+23 7575827 2 10
+23 7575827 3 10
+23 7575827 4 10
+23 7575827 5 10
+23 4135707 1 5
+23 4135707 2 5
+23 4135707 3 5
+23 4135707 4 5
+23 4135707 5 5
+23 5834316 1 0
+23 5834316 2 0
+23 5834316 3 0
+23 5834316 4 0
+23 5834316 5 0
+23 5605190 1 2
+23 5605190 2 2
+23 5605190 3 2
+23 5605190 4 2
+23 5605190 5 2
+23 3412980 1 4
+23 3412980 2 4
+23 3412980 3 4
+23 3412980 4 4
+23 3412980 5 4
+23 2337431 1 10
+23 2337431 2 10
+23 2337431 3 10
+23 2337431 4 10
+23 2337431 5 10
+23 1248504 1 17
+23 1248504 2 17
+23 1248504 3 17
+23 1248504 4 17
+23 1248504 5 17
+23 2425452 1 14
+23 2425452 2 14
+23 2425452 3 14
+23 2425452 4 14
+23 2425452 5 14
+23 5214096 1 6
+23 5214096 2 6
+23 5214096 3 6
+23 5214096 4 6
+23 5214096 5 6
+23 1257705 1 8
+23 1257705 2 8
+23 1257705 3 8
+23 1257705 4 8
+23 1257705 5 8
+23 527815 1 12
+23 527815 2 12
+23 527815 3 12
+23 527815 4 12
+23 527815 5 12
+23 4250399 1 5
+23 4250399 2 5
+23 4250399 3 5
+23 4250399 4 5
+23 4250399 5 5
+23 1200698 1 4
+23 1200698 2 4
+23 1200698 3 4
+23 1200698 4 4
+23 1200698 5 4
+23 4310378 1 8
+23 4310378 2 8
+23 4310378 3 8
+23 4310378 4 8
+23 4310378 5 8
+23 724255 1 6
+23 724255 2 6
+23 724255 3 6
+23 724255 4 6
+23 724255 5 6
+23 5100058 1 9
+23 5100058 2 9
+23 5100058 3 9
+23 5100058 4 9
+23 5100058 5 9
+23 6466953 1 4
+23 6466953 2 4
+23 6466953 3 4
+23 6466953 4 4
+23 6466953 5 4
+23 181844 1 17
+23 181844 2 17
+23 181844 3 17
+23 181844 4 17
+23 181844 5 17
+23 527081 1 15
+23 527081 2 15
+23 527081 3 15
+23 527081 4 15
+23 527081 5 15
+23 194874 1 0
+23 194874 2 0
+23 194874 3 0
+23 194874 4 0
+23 194874 5 0
+23 5612248 1 7
+23 5612248 2 7
+23 5612248 3 7
+23 5612248 4 7
+23 5612248 5 7
+23 2969929 1 15
+23 2969929 2 15
+23 2969929 3 15
+23 2969929 4 15
+23 2969929 5 15
+23 7237394 1 15
+23 7237394 2 15
+23 7237394 3 15
+23 7237394 4 15
+23 7237394 5 15
+23 865283 1 7
+23 865283 2 7
+23 865283 3 7
+23 865283 4 7
+23 865283 5 7
+23 235461 1 3
+23 235461 2 3
+23 235461 3 3
+23 235461 4 3
+23 235461 5 3
+23 6769613 1 0
+23 6769613 2 0
+23 6769613 3 0
+23 6769613 4 0
+23 6769613 5 0
+23 5015052 1 7
+23 5015052 2 7
+23 5015052 3 7
+23 5015052 4 7
+23 5015052 5 7
+23 3295257 1 13
+23 3295257 2 13
+23 3295257 3 13
+23 3295257 4 13
+23 3295257 5 13
+23 989877 1 1
+23 989877 2 1
+23 989877 3 1
+23 989877 4 1
+23 989877 5 1
+23 1637319 1 13
+23 1637319 2 13
+23 1637319 3 13
+23 1637319 4 13
+23 1637319 5 13
+23 3018058 1 13
+23 3018058 2 13
+23 3018058 3 13
+23 3018058 4 13
+23 3018058 5 13
+24 9775649 1 12
+24 9775649 2 12
+24 9775649 3 12
+24 9775649 4 12
+24 9775649 5 12
+24 14133895 1 9
+24 14133895 2 9
+24 14133895 3 9
+24 14133895 4 9
+24 14133895 5 9
+24 3743280 1 17
+24 3743280 2 17
+24 3743280 3 17
+24 3743280 4 17
+24 3743280 5 17
+24 1023898 1 3
+24 1023898 2 3
+24 1023898 3 3
+24 1023898 4 3
+24 1023898 5 3
+24 9941521 1 3
+24 9941521 2 3
+24 9941521 3 3
+24 9941521 4 3
+24 9941521 5 3
+24 10377160 1 3
+24 10377160 2 3
+24 10377160 3 3
+24 10377160 4 3
+24 10377160 5 3
+24 11342584 1 1
+24 11342584 2 1
+24 11342584 3 1
+24 11342584 4 1
+24 11342584 5 1
+24 9294179 1 1
+24 9294179 2 1
+24 9294179 3 1
+24 9294179 4 1
+24 9294179 5 1
+24 15025827 1 9
+24 15025827 2 9
+24 15025827 3 9
+24 15025827 4 9
+24 15025827 5 9
+24 3498285 1 14
+24 3498285 2 14
+24 3498285 3 14
+24 3498285 4 14
+24 3498285 5 14
+24 8199923 1 13
+24 8199923 2 13
+24 8199923 3 13
+24 8199923 4 13
+24 8199923 5 13
+24 90634 1 1
+24 90634 2 1
+24 90634 3 1
+24 90634 4 1
+24 90634 5 1
+24 12997310 1 6
+24 12997310 2 6
+24 12997310 3 6
+24 12997310 4 6
+24 12997310 5 6
+24 14265335 1 17
+24 14265335 2 17
+24 14265335 3 17
+24 14265335 4 17
+24 14265335 5 17
+24 5492707 1 13
+24 5492707 2 13
+24 5492707 3 13
+24 5492707 4 13
+24 5492707 5 13
+24 263738 1 13
+24 263738 2 13
+24 263738 3 13
+24 263738 4 13
+24 263738 5 13
+24 13671070 1 4
+24 13671070 2 4
+24 13671070 3 4
+24 13671070 4 4
+24 13671070 5 4
+24 8325339 1 0
+24 8325339 2 0
+24 8325339 3 0
+24 8325339 4 0
+24 8325339 5 0
+24 9752092 1 8
+24 9752092 2 8
+24 9752092 3 8
+24 9752092 4 8
+24 9752092 5 8
+24 10821970 1 5
+24 10821970 2 5
+24 10821970 3 5
+24 10821970 4 5
+24 10821970 5 5
+24 3248722 1 0
+24 3248722 2 0
+24 3248722 3 0
+24 3248722 4 0
+24 3248722 5 0
+24 11447937 1 12
+24 11447937 2 12
+24 11447937 3 12
+24 11447937 4 12
+24 11447937 5 12
+24 6691593 1 6
+24 6691593 2 6
+24 6691593 3 6
+24 6691593 4 6
+24 6691593 5 6
+24 10840036 1 7
+24 10840036 2 7
+24 10840036 3 7
+24 10840036 4 7
+24 10840036 5 7
+24 8193085 1 3
+24 8193085 2 3
+24 8193085 3 3
+24 8193085 4 3
+24 8193085 5 3
+24 13272070 1 17
+24 13272070 2 17
+24 13272070 3 17
+24 13272070 4 17
+24 13272070 5 17
+24 3317672 1 8
+24 3317672 2 8
+24 3317672 3 8
+24 3317672 4 8
+24 3317672 5 8
+24 9720374 1 6
+24 9720374 2 6
+24 9720374 3 6
+24 9720374 4 6
+24 9720374 5 6
+24 3803032 1 15
+24 3803032 2 15
+24 3803032 3 15
+24 3803032 4 15
+24 3803032 5 15
+24 8338298 1 12
+24 8338298 2 12
+24 8338298 3 12
+24 8338298 4 12
+24 8338298 5 12
+24 8391433 1 8
+24 8391433 2 8
+24 8391433 3 8
+24 8391433 4 8
+24 8391433 5 8
+24 3759812 1 17
+24 3759812 2 17
+24 3759812 3 17
+24 3759812 4 17
+24 3759812 5 17
+24 11028207 1 17
+24 11028207 2 17
+24 11028207 3 17
+24 11028207 4 17
+24 11028207 5 17
+24 7289955 1 15
+24 7289955 2 15
+24 7289955 3 15
+24 7289955 4 15
+24 7289955 5 15
+24 3277010 1 9
+24 3277010 2 9
+24 3277010 3 9
+24 3277010 4 9
+24 3277010 5 9
+24 15934652 1 4
+24 15934652 2 4
+24 15934652 3 4
+24 15934652 4 4
+24 15934652 5 4
+24 7837344 1 0
+24 7837344 2 0
+24 7837344 3 0
+24 7837344 4 0
+24 7837344 5 0
+24 6315577 1 15
+24 6315577 2 15
+24 6315577 3 15
+24 6315577 4 15
+24 6315577 5 15
+24 9738174 1 10
+24 9738174 2 10
+24 9738174 3 10
+24 9738174 4 10
+24 9738174 5 10
+24 16135808 1 4
+24 16135808 2 4
+24 16135808 3 4
+24 16135808 4 4
+24 16135808 5 4
+24 7068511 1 10
+24 7068511 2 10
+24 7068511 3 10
+24 7068511 4 10
+24 7068511 5 10
+24 7762664 1 5
+24 7762664 2 5
+24 7762664 3 5
+24 7762664 4 5
+24 7762664 5 5
+24 13117465 1 10
+24 13117465 2 10
+24 13117465 3 10
+24 13117465 4 10
+24 13117465 5 10
+24 9819176 1 9
+24 9819176 2 9
+24 9819176 3 9
+24 9819176 4 9
+24 9819176 5 9
+24 2572469 1 1
+24 2572469 2 1
+24 2572469 3 1
+24 2572469 4 1
+24 2572469 5 1
+24 4497745 1 1
+24 4497745 2 1
+24 4497745 3 1
+24 4497745 4 1
+24 4497745 5 1
+24 6842950 1 0
+24 6842950 2 0
+24 6842950 3 0
+24 6842950 4 0
+24 6842950 5 0
+24 28157 1 14
+24 28157 2 14
+24 28157 3 14
+24 28157 4 14
+24 28157 5 14
+24 9748348 1 15
+24 9748348 2 15
+24 9748348 3 15
+24 9748348 4 15
+24 9748348 5 15
+24 12554184 1 8
+24 12554184 2 8
+24 12554184 3 8
+24 12554184 4 8
+24 12554184 5 8
+24 8971577 1 4
+24 8971577 2 4
+24 8971577 3 4
+24 8971577 4 4
+24 8971577 5 4
+24 1701631 1 9
+24 1701631 2 9
+24 1701631 3 9
+24 1701631 4 9
+24 1701631 5 9
+24 11334757 1 6
+24 11334757 2 6
+24 11334757 3 6
+24 11334757 4 6
+24 11334757 5 6
+24 5922455 1 10
+24 5922455 2 10
+24 5922455 3 10
+24 5922455 4 10
+24 5922455 5 10
+24 6335742 1 7
+24 6335742 2 7
+24 6335742 3 7
+24 6335742 4 7
+24 6335742 5 7
+24 6162272 1 6
+24 6162272 2 6
+24 6162272 3 6
+24 6162272 4 6
+24 6162272 5 6
+24 9389682 1 3
+24 9389682 2 3
+24 9389682 3 3
+24 9389682 4 3
+24 9389682 5 3
+24 14185082 1 9
+24 14185082 2 9
+24 14185082 3 9
+24 14185082 4 9
+24 14185082 5 9
+24 4157744 1 1
+24 4157744 2 1
+24 4157744 3 1
+24 4157744 4 1
+24 4157744 5 1
+24 15978247 1 6
+24 15978247 2 6
+24 15978247 3 6
+24 15978247 4 6
+24 15978247 5 6
+24 2710908 1 7
+24 2710908 2 7
+24 2710908 3 7
+24 2710908 4 7
+24 2710908 5 7
+24 10358562 1 5
+24 10358562 2 5
+24 10358562 3 5
+24 10358562 4 5
+24 10358562 5 5
+24 10869634 1 15
+24 10869634 2 15
+24 10869634 3 15
+24 10869634 4 15
+24 10869634 5 15
+24 6150158 1 17
+24 6150158 2 17
+24 6150158 3 17
+24 6150158 4 17
+24 6150158 5 17
+25 27898613 1 5
+25 27898613 2 5
+25 27898613 3 5
+25 27898613 4 5
+25 27898613 5 5
+25 29501 1 1
+25 29501 2 1
+25 29501 3 1
+25 29501 4 1
+25 29501 5 1
+25 15761162 1 8
+25 15761162 2 8
+25 15761162 3 8
+25 15761162 4 8
+25 15761162 5 8
+25 15728788 1 14
+25 15728788 2 14
+25 15728788 3 14
+25 15728788 4 14
+25 15728788 5 14
+25 33257945 1 14
+25 33257945 2 14
+25 33257945 3 14
+25 33257945 4 14
+25 33257945 5 14
+25 25725432 1 1
+25 25725432 2 1
+25 25725432 3 1
+25 25725432 4 1
+25 25725432 5 1
+25 32158340 1 4
+25 32158340 2 4
+25 32158340 3 4
+25 32158340 4 4
+25 32158340 5 4
+25 14232919 1 6
+25 14232919 2 6
+25 14232919 3 6
+25 14232919 4 6
+25 14232919 5 6
+25 25835501 1 6
+25 25835501 2 6
+25 25835501 3 6
+25 25835501 4 6
+25 25835501 5 6
+25 17975125 1 17
+25 17975125 2 17
+25 17975125 3 17
+25 17975125 4 17
+25 17975125 5 17
+25 1306676 1 9
+25 1306676 2 9
+25 1306676 3 9
+25 1306676 4 9
+25 1306676 5 9
+25 15859824 1 7
+25 15859824 2 7
+25 15859824 3 7
+25 15859824 4 7
+25 15859824 5 7
+25 28894333 1 4
+25 28894333 2 4
+25 28894333 3 4
+25 28894333 4 4
+25 28894333 5 4
+25 9046116 1 15
+25 9046116 2 15
+25 9046116 3 15
+25 9046116 4 15
+25 9046116 5 15
+25 26019062 1 13
+25 26019062 2 13
+25 26019062 3 13
+25 26019062 4 13
+25 26019062 5 13
+25 1778640 1 9
+25 1778640 2 9
+25 1778640 3 9
+25 1778640 4 9
+25 1778640 5 9
+25 10266904 1 1
+25 10266904 2 1
+25 10266904 3 1
+25 10266904 4 1
+25 10266904 5 1
+25 6909977 1 3
+25 6909977 2 3
+25 6909977 3 3
+25 6909977 4 3
+25 6909977 5 3
+25 10702892 1 2
+25 10702892 2 2
+25 10702892 3 2
+25 10702892 4 2
+25 10702892 5 2
+25 11960717 1 6
+25 11960717 2 6
+25 11960717 3 6
+25 11960717 4 6
+25 11960717 5 6
+25 5203472 1 1
+25 5203472 2 1
+25 5203472 3 1
+25 5203472 4 1
+25 5203472 5 1
+25 29147083 1 17
+25 29147083 2 17
+25 29147083 3 17
+25 29147083 4 17
+25 29147083 5 17
+25 24580154 1 6
+25 24580154 2 6
+25 24580154 3 6
+25 24580154 4 6
+25 24580154 5 6
+25 14263395 1 8
+25 14263395 2 8
+25 14263395 3 8
+25 14263395 4 8
+25 14263395 5 8
+25 22955773 1 7
+25 22955773 2 7
+25 22955773 3 7
+25 22955773 4 7
+25 22955773 5 7
+25 21675961 1 8
+25 21675961 2 8
+25 21675961 3 8
+25 21675961 4 8
+25 21675961 5 8
+25 7257867 1 8
+25 7257867 2 8
+25 7257867 3 8
+25 7257867 4 8
+25 7257867 5 8
+25 20686894 1 5
+25 20686894 2 5
+25 20686894 3 5
+25 20686894 4 5
+25 20686894 5 5
+25 29779770 1 0
+25 29779770 2 0
+25 29779770 3 0
+25 29779770 4 0
+25 29779770 5 0
+25 27342720 1 8
+25 27342720 2 8
+25 27342720 3 8
+25 27342720 4 8
+25 27342720 5 8
+25 622218 1 9
+25 622218 2 9
+25 622218 3 9
+25 622218 4 9
+25 622218 5 9
+25 12630641 1 8
+25 12630641 2 8
+25 12630641 3 8
+25 12630641 4 8
+25 12630641 5 8
+25 3245670 1 0
+25 3245670 2 0
+25 3245670 3 0
+25 3245670 4 0
+25 3245670 5 0
+25 521894 1 8
+25 521894 2 8
+25 521894 3 8
+25 521894 4 8
+25 521894 5 8
+25 14849322 1 2
+25 14849322 2 2
+25 14849322 3 2
+25 14849322 4 2
+25 14849322 5 2
+25 12921554 1 8
+25 12921554 2 8
+25 12921554 3 8
+25 12921554 4 8
+25 12921554 5 8
+25 23383269 1 3
+25 23383269 2 3
+25 23383269 3 3
+25 23383269 4 3
+25 23383269 5 3
+25 10251539 1 2
+25 10251539 2 2
+25 10251539 3 2
+25 10251539 4 2
+25 10251539 5 2
+25 16251487 1 14
+25 16251487 2 14
+25 16251487 3 14
+25 16251487 4 14
+25 16251487 5 14
+25 9046939 1 3
+25 9046939 2 3
+25 9046939 3 3
+25 9046939 4 3
+25 9046939 5 3
+25 1286237 1 10
+25 1286237 2 10
+25 1286237 3 10
+25 1286237 4 10
+25 1286237 5 10
+25 1561491 1 6
+25 1561491 2 6
+25 1561491 3 6
+25 1561491 4 6
+25 1561491 5 6
+25 25555747 1 2
+25 25555747 2 2
+25 25555747 3 2
+25 25555747 4 2
+25 25555747 5 2
+25 6644283 1 17
+25 6644283 2 17
+25 6644283 3 17
+25 6644283 4 17
+25 6644283 5 17
+25 25724985 1 6
+25 25724985 2 6
+25 25724985 3 6
+25 25724985 4 6
+25 25724985 5 6
+25 123989 1 14
+25 123989 2 14
+25 123989 3 14
+25 123989 4 14
+25 123989 5 14
+25 17415794 1 7
+25 17415794 2 7
+25 17415794 3 7
+25 17415794 4 7
+25 17415794 5 7
+25 26732483 1 12
+25 26732483 2 12
+25 26732483 3 12
+25 26732483 4 12
+25 26732483 5 12
+25 30810665 1 14
+25 30810665 2 14
+25 30810665 3 14
+25 30810665 4 14
+25 30810665 5 14
+25 5383023 1 6
+25 5383023 2 6
+25 5383023 3 6
+25 5383023 4 6
+25 5383023 5 6
+25 20795854 1 1
+25 20795854 2 1
+25 20795854 3 1
+25 20795854 4 1
+25 20795854 5 1
+25 32135530 1 6
+25 32135530 2 6
+25 32135530 3 6
+25 32135530 4 6
+25 32135530 5 6
+25 8529568 1 15
+25 8529568 2 15
+25 8529568 3 15
+25 8529568 4 15
+25 8529568 5 15
+25 29472599 1 15
+25 29472599 2 15
+25 29472599 3 15
+25 29472599 4 15
+25 29472599 5 15
+25 18752955 1 7
+25 18752955 2 7
+25 18752955 3 7
+25 18752955 4 7
+25 18752955 5 7
+25 7624970 1 12
+25 7624970 2 12
+25 7624970 3 12
+25 7624970 4 12
+25 7624970 5 12
+25 14450005 1 17
+25 14450005 2 17
+25 14450005 3 17
+25 14450005 4 17
+25 14450005 5 17
+25 5230955 1 1
+25 5230955 2 1
+25 5230955 3 1
+25 5230955 4 1
+25 5230955 5 1
+25 22090308 1 5
+25 22090308 2 5
+25 22090308 3 5
+25 22090308 4 5
+25 22090308 5 5
+25 19848608 1 9
+25 19848608 2 9
+25 19848608 3 9
+25 19848608 4 9
+25 19848608 5 9
+25 24404419 1 6
+25 24404419 2 6
+25 24404419 3 6
+25 24404419 4 6
+25 24404419 5 6
+25 29009514 1 14
+25 29009514 2 14
+25 29009514 3 14
+25 29009514 4 14
+25 29009514 5 14
+25 24460148 1 6
+25 24460148 2 6
+25 24460148 3 6
+25 24460148 4 6
+25 24460148 5 6
+25 20198351 1 10
+25 20198351 2 10
+25 20198351 3 10
+25 20198351 4 10
+25 20198351 5 10
+26 7084154 1 9
+26 7084154 2 9
+26 7084154 3 9
+26 7084154 4 9
+26 7084154 5 9
+26 25565466 1 9
+26 25565466 2 9
+26 25565466 3 9
+26 25565466 4 9
+26 25565466 5 9
+26 46816379 1 15
+26 46816379 2 15
+26 46816379 3 15
+26 46816379 4 15
+26 46816379 5 15
+26 21945765 1 1
+26 21945765 2 1
+26 21945765 3 1
+26 21945765 4 1
+26 21945765 5 1
+26 13640323 1 17
+26 13640323 2 17
+26 13640323 3 17
+26 13640323 4 17
+26 13640323 5 17
+26 30012262 1 13
+26 30012262 2 13
+26 30012262 3 13
+26 30012262 4 13
+26 30012262 5 13
+26 20042720 1 5
+26 20042720 2 5
+26 20042720 3 5
+26 20042720 4 5
+26 20042720 5 5
+26 16193914 1 6
+26 16193914 2 6
+26 16193914 3 6
+26 16193914 4 6
+26 16193914 5 6
+26 10183696 1 4
+26 10183696 2 4
+26 10183696 3 4
+26 10183696 4 4
+26 10183696 5 4
+26 24876252 1 0
+26 24876252 2 0
+26 24876252 3 0
+26 24876252 4 0
+26 24876252 5 0
+26 5209203 1 13
+26 5209203 2 13
+26 5209203 3 13
+26 5209203 4 13
+26 5209203 5 13
+26 18883903 1 17
+26 18883903 2 17
+26 18883903 3 17
+26 18883903 4 17
+26 18883903 5 17
+26 48312129 1 5
+26 48312129 2 5
+26 48312129 3 5
+26 48312129 4 5
+26 48312129 5 5
+26 24703773 1 7
+26 24703773 2 7
+26 24703773 3 7
+26 24703773 4 7
+26 24703773 5 7
+26 65103293 1 2
+26 65103293 2 2
+26 65103293 3 2
+26 65103293 4 2
+26 65103293 5 2
+26 64342799 1 8
+26 64342799 2 8
+26 64342799 3 8
+26 64342799 4 8
+26 64342799 5 8
+26 54033834 1 10
+26 54033834 2 10
+26 54033834 3 10
+26 54033834 4 10
+26 54033834 5 10
+26 11156063 1 17
+26 11156063 2 17
+26 11156063 3 17
+26 11156063 4 17
+26 11156063 5 17
+26 58182142 1 9
+26 58182142 2 9
+26 58182142 3 9
+26 58182142 4 9
+26 58182142 5 9
+26 25321691 1 10
+26 25321691 2 10
+26 25321691 3 10
+26 25321691 4 10
+26 25321691 5 10
+26 49670869 1 10
+26 49670869 2 10
+26 49670869 3 10
+26 49670869 4 10
+26 49670869 5 10
+26 9604075 1 6
+26 9604075 2 6
+26 9604075 3 6
+26 9604075 4 6
+26 9604075 5 6
+26 21246120 1 17
+26 21246120 2 17
+26 21246120 3 17
+26 21246120 4 17
+26 21246120 5 17
+26 54324966 1 15
+26 54324966 2 15
+26 54324966 3 15
+26 54324966 4 15
+26 54324966 5 15
+26 12222142 1 4
+26 12222142 2 4
+26 12222142 3 4
+26 12222142 4 4
+26 12222142 5 4
+26 46795936 1 10
+26 46795936 2 10
+26 46795936 3 10
+26 46795936 4 10
+26 46795936 5 10
+26 28991713 1 0
+26 28991713 2 0
+26 28991713 3 0
+26 28991713 4 0
+26 28991713 5 0
+26 21341767 1 6
+26 21341767 2 6
+26 21341767 3 6
+26 21341767 4 6
+26 21341767 5 6
+26 35735637 1 15
+26 35735637 2 15
+26 35735637 3 15
+26 35735637 4 15
+26 35735637 5 15
+26 20661103 1 13
+26 20661103 2 13
+26 20661103 3 13
+26 20661103 4 13
+26 20661103 5 13
+26 40707078 1 6
+26 40707078 2 6
+26 40707078 3 6
+26 40707078 4 6
+26 40707078 5 6
+26 53127018 1 12
+26 53127018 2 12
+26 53127018 3 12
+26 53127018 4 12
+26 53127018 5 12
+26 43370495 1 7
+26 43370495 2 7
+26 43370495 3 7
+26 43370495 4 7
+26 43370495 5 7
+26 4048861 1 10
+26 4048861 2 10
+26 4048861 3 10
+26 4048861 4 10
+26 4048861 5 10
+26 30464035 1 15
+26 30464035 2 15
+26 30464035 3 15
+26 30464035 4 15
+26 30464035 5 15
+26 5183631 1 9
+26 5183631 2 9
+26 5183631 3 9
+26 5183631 4 9
+26 5183631 5 9
+26 27077142 1 1
+26 27077142 2 1
+26 27077142 3 1
+26 27077142 4 1
+26 27077142 5 1
+26 48775300 1 6
+26 48775300 2 6
+26 48775300 3 6
+26 48775300 4 6
+26 48775300 5 6
+26 13488763 1 12
+26 13488763 2 12
+26 13488763 3 12
+26 13488763 4 12
+26 13488763 5 12
+26 13536330 1 8
+26 13536330 2 8
+26 13536330 3 8
+26 13536330 4 8
+26 13536330 5 8
+26 35410276 1 9
+26 35410276 2 9
+26 35410276 3 9
+26 35410276 4 9
+26 35410276 5 9
+26 53719442 1 12
+26 53719442 2 12
+26 53719442 3 12
+26 53719442 4 12
+26 53719442 5 12
+26 38572550 1 8
+26 38572550 2 8
+26 38572550 3 8
+26 38572550 4 8
+26 38572550 5 8
+26 66500609 1 4
+26 66500609 2 4
+26 66500609 3 4
+26 66500609 4 4
+26 66500609 5 4
+26 56930732 1 5
+26 56930732 2 5
+26 56930732 3 5
+26 56930732 4 5
+26 56930732 5 5
+26 13245256 1 7
+26 13245256 2 7
+26 13245256 3 7
+26 13245256 4 7
+26 13245256 5 7
+26 2474478 1 9
+26 2474478 2 9
+26 2474478 3 9
+26 2474478 4 9
+26 2474478 5 9
+26 47282801 1 12
+26 47282801 2 12
+26 47282801 3 12
+26 47282801 4 12
+26 47282801 5 12
+26 1178146 1 3
+26 1178146 2 3
+26 1178146 3 3
+26 1178146 4 3
+26 1178146 5 3
+26 43673724 1 6
+26 43673724 2 6
+26 43673724 3 6
+26 43673724 4 6
+26 43673724 5 6
+26 2100241 1 6
+26 2100241 2 6
+26 2100241 3 6
+26 2100241 4 6
+26 2100241 5 6
+26 41497130 1 0
+26 41497130 2 0
+26 41497130 3 0
+26 41497130 4 0
+26 41497130 5 0
+26 33722349 1 2
+26 33722349 2 2
+26 33722349 3 2
+26 33722349 4 2
+26 33722349 5 2
+26 9153815 1 12
+26 9153815 2 12
+26 9153815 3 12
+26 9153815 4 12
+26 9153815 5 12
+26 48610178 1 7
+26 48610178 2 7
+26 48610178 3 7
+26 48610178 4 7
+26 48610178 5 7
+26 53568526 1 14
+26 53568526 2 14
+26 53568526 3 14
+26 53568526 4 14
+26 53568526 5 14
+26 32823468 1 2
+26 32823468 2 2
+26 32823468 3 2
+26 32823468 4 2
+26 32823468 5 2
+26 65647768 1 14
+26 65647768 2 14
+26 65647768 3 14
+26 65647768 4 14
+26 65647768 5 14
+26 35401480 1 15
+26 35401480 2 15
+26 35401480 3 15
+26 35401480 4 15
+26 35401480 5 15
+26 41791958 1 12
+26 41791958 2 12
+26 41791958 3 12
+26 41791958 4 12
+26 41791958 5 12
+26 9655534 1 8
+26 9655534 2 8
+26 9655534 3 8
+26 9655534 4 8
+26 9655534 5 8
+26 40165520 1 1
+26 40165520 2 1
+26 40165520 3 1
+26 40165520 4 1
+26 40165520 5 1
+26 34020254 1 12
+26 34020254 2 12
+26 34020254 3 12
+26 34020254 4 12
+26 34020254 5 12
+26 61939853 1 8
+26 61939853 2 8
+26 61939853 3 8
+26 61939853 4 8
+26 61939853 5 8
+27 92315981 1 2
+27 92315981 2 2
+27 92315981 3 2
+27 92315981 4 2
+27 92315981 5 2
+27 61792721 1 8
+27 61792721 2 8
+27 61792721 3 8
+27 61792721 4 8
+27 61792721 5 8
+27 92388693 1 1
+27 92388693 2 1
+27 92388693 3 1
+27 92388693 4 1
+27 92388693 5 1
+27 53427871 1 17
+27 53427871 2 17
+27 53427871 3 17
+27 53427871 4 17
+27 53427871 5 17
+27 120842826 1 9
+27 120842826 2 9
+27 120842826 3 9
+27 120842826 4 9
+27 120842826 5 9
+27 28583319 1 10
+27 28583319 2 10
+27 28583319 3 10
+27 28583319 4 10
+27 28583319 5 10
+27 124744556 1 9
+27 124744556 2 9
+27 124744556 3 9
+27 124744556 4 9
+27 124744556 5 9
+27 4355438 1 0
+27 4355438 2 0
+27 4355438 3 0
+27 4355438 4 0
+27 4355438 5 0
+27 4216154 1 9
+27 4216154 2 9
+27 4216154 3 9
+27 4216154 4 9
+27 4216154 5 9
+27 123239172 1 13
+27 123239172 2 13
+27 123239172 3 13
+27 123239172 4 13
+27 123239172 5 13
+27 115756467 1 4
+27 115756467 2 4
+27 115756467 3 4
+27 115756467 4 4
+27 115756467 5 4
+27 51430308 1 9
+27 51430308 2 9
+27 51430308 3 9
+27 51430308 4 9
+27 51430308 5 9
+27 64209151 1 13
+27 64209151 2 13
+27 64209151 3 13
+27 64209151 4 13
+27 64209151 5 13
+27 86593418 1 6
+27 86593418 2 6
+27 86593418 3 6
+27 86593418 4 6
+27 86593418 5 6
+27 18520784 1 17
+27 18520784 2 17
+27 18520784 3 17
+27 18520784 4 17
+27 18520784 5 17
+27 99412133 1 3
+27 99412133 2 3
+27 99412133 3 3
+27 99412133 4 3
+27 99412133 5 3
+27 17075236 1 6
+27 17075236 2 6
+27 17075236 3 6
+27 17075236 4 6
+27 17075236 5 6
+27 9740701 1 10
+27 9740701 2 10
+27 9740701 3 10
+27 9740701 4 10
+27 9740701 5 10
+27 42355725 1 17
+27 42355725 2 17
+27 42355725 3 17
+27 42355725 4 17
+27 42355725 5 17
+27 76792086 1 12
+27 76792086 2 12
+27 76792086 3 12
+27 76792086 4 12
+27 76792086 5 12
+27 34848403 1 4
+27 34848403 2 4
+27 34848403 3 4
+27 34848403 4 4
+27 34848403 5 4
+27 60857654 1 4
+27 60857654 2 4
+27 60857654 3 4
+27 60857654 4 4
+27 60857654 5 4
+27 89466329 1 1
+27 89466329 2 1
+27 89466329 3 1
+27 89466329 4 1
+27 89466329 5 1
+27 7416677 1 0
+27 7416677 2 0
+27 7416677 3 0
+27 7416677 4 0
+27 7416677 5 0
+27 94093693 1 17
+27 94093693 2 17
+27 94093693 3 17
+27 94093693 4 17
+27 94093693 5 17
+27 71977043 1 0
+27 71977043 2 0
+27 71977043 3 0
+27 71977043 4 0
+27 71977043 5 0
+27 32931909 1 1
+27 32931909 2 1
+27 32931909 3 1
+27 32931909 4 1
+27 32931909 5 1
+27 99417150 1 1
+27 99417150 2 1
+27 99417150 3 1
+27 99417150 4 1
+27 99417150 5 1
+27 78489591 1 5
+27 78489591 2 5
+27 78489591 3 5
+27 78489591 4 5
+27 78489591 5 5
+27 56442740 1 17
+27 56442740 2 17
+27 56442740 3 17
+27 56442740 4 17
+27 56442740 5 17
+27 49715079 1 8
+27 49715079 2 8
+27 49715079 3 8
+27 49715079 4 8
+27 49715079 5 8
+27 95552279 1 5
+27 95552279 2 5
+27 95552279 3 5
+27 95552279 4 5
+27 95552279 5 5
+27 119474039 1 13
+27 119474039 2 13
+27 119474039 3 13
+27 119474039 4 13
+27 119474039 5 13
+27 47612448 1 12
+27 47612448 2 12
+27 47612448 3 12
+27 47612448 4 12
+27 47612448 5 12
+27 125922426 1 14
+27 125922426 2 14
+27 125922426 3 14
+27 125922426 4 14
+27 125922426 5 14
+27 18947749 1 8
+27 18947749 2 8
+27 18947749 3 8
+27 18947749 4 8
+27 18947749 5 8
+27 92954715 1 5
+27 92954715 2 5
+27 92954715 3 5
+27 92954715 4 5
+27 92954715 5 5
+27 69488478 1 7
+27 69488478 2 7
+27 69488478 3 7
+27 69488478 4 7
+27 69488478 5 7
+27 36779293 1 0
+27 36779293 2 0
+27 36779293 3 0
+27 36779293 4 0
+27 36779293 5 0
+27 90333541 1 4
+27 90333541 2 4
+27 90333541 3 4
+27 90333541 4 4
+27 90333541 5 4
+27 113514082 1 1
+27 113514082 2 1
+27 113514082 3 1
+27 113514082 4 1
+27 113514082 5 1
+27 114627133 1 2
+27 114627133 2 2
+27 114627133 3 2
+27 114627133 4 2
+27 114627133 5 2
+27 67788048 1 12
+27 67788048 2 12
+27 67788048 3 12
+27 67788048 4 12
+27 67788048 5 12
+27 80102932 1 6
+27 80102932 2 6
+27 80102932 3 6
+27 80102932 4 6
+27 80102932 5 6
+27 80083249 1 4
+27 80083249 2 4
+27 80083249 3 4
+27 80083249 4 4
+27 80083249 5 4
+27 8871500 1 0
+27 8871500 2 0
+27 8871500 3 0
+27 8871500 4 0
+27 8871500 5 0
+27 96933402 1 10
+27 96933402 2 10
+27 96933402 3 10
+27 96933402 4 10
+27 96933402 5 10
+27 40432695 1 17
+27 40432695 2 17
+27 40432695 3 17
+27 40432695 4 17
+27 40432695 5 17
+27 55794895 1 13
+27 55794895 2 13
+27 55794895 3 13
+27 55794895 4 13
+27 55794895 5 13
+27 120388642 1 6
+27 120388642 2 6
+27 120388642 3 6
+27 120388642 4 6
+27 120388642 5 6
+27 64256165 1 0
+27 64256165 2 0
+27 64256165 3 0
+27 64256165 4 0
+27 64256165 5 0
+27 4822164 1 0
+27 4822164 2 0
+27 4822164 3 0
+27 4822164 4 0
+27 4822164 5 0
+27 14139945 1 12
+27 14139945 2 12
+27 14139945 3 12
+27 14139945 4 12
+27 14139945 5 12
+27 116590039 1 0
+27 116590039 2 0
+27 116590039 3 0
+27 116590039 4 0
+27 116590039 5 0
+27 61027392 1 6
+27 61027392 2 6
+27 61027392 3 6
+27 61027392 4 6
+27 61027392 5 6
+27 71808439 1 4
+27 71808439 2 4
+27 71808439 3 4
+27 71808439 4 4
+27 71808439 5 4
+27 4329359 1 4
+27 4329359 2 4
+27 4329359 3 4
+27 4329359 4 4
+27 4329359 5 4
+27 90248073 1 2
+27 90248073 2 2
+27 90248073 3 2
+27 90248073 4 2
+27 90248073 5 2
+27 53334044 1 17
+27 53334044 2 17
+27 53334044 3 17
+27 53334044 4 17
+27 53334044 5 17
+27 79216751 1 12
+27 79216751 2 12
+27 79216751 3 12
+27 79216751 4 12
+27 79216751 5 12
+27 14571829 1 6
+27 14571829 2 6
+27 14571829 3 6
+27 14571829 4 6
+27 14571829 5 6
+27 58816473 1 5
+27 58816473 2 5
+27 58816473 3 5
+27 58816473 4 5
+27 58816473 5 5
+27 97942416 1 15
+27 97942416 2 15
+27 97942416 3 15
+27 97942416 4 15
+27 97942416 5 15
+27 25656398 1 9
+27 25656398 2 9
+27 25656398 3 9
+27 25656398 4 9
+27 25656398 5 9
+28 115821936 1 15
+28 115821936 2 15
+28 115821936 3 15
+28 115821936 4 15
+28 115821936 5 15
+28 108711265 1 3
+28 108711265 2 3
+28 108711265 3 3
+28 108711265 4 3
+28 108711265 5 3
+28 51814809 1 8
+28 51814809 2 8
+28 51814809 3 8
+28 51814809 4 8
+28 51814809 5 8
+28 9511812 1 3
+28 9511812 2 3
+28 9511812 3 3
+28 9511812 4 3
+28 9511812 5 3
+28 119984430 1 14
+28 119984430 2 14
+28 119984430 3 14
+28 119984430 4 14
+28 119984430 5 14
+28 222765195 1 1
+28 222765195 2 1
+28 222765195 3 1
+28 222765195 4 1
+28 222765195 5 1
+28 44273960 1 13
+28 44273960 2 13
+28 44273960 3 13
+28 44273960 4 13
+28 44273960 5 13
+28 146489653 1 8
+28 146489653 2 8
+28 146489653 3 8
+28 146489653 4 8
+28 146489653 5 8
+28 242813898 1 9
+28 242813898 2 9
+28 242813898 3 9
+28 242813898 4 9
+28 242813898 5 9
+28 145291726 1 6
+28 145291726 2 6
+28 145291726 3 6
+28 145291726 4 6
+28 145291726 5 6
+28 64513013 1 1
+28 64513013 2 1
+28 64513013 3 1
+28 64513013 4 1
+28 64513013 5 1
+28 214162337 1 13
+28 214162337 2 13
+28 214162337 3 13
+28 214162337 4 13
+28 214162337 5 13
+28 210803129 1 2
+28 210803129 2 2
+28 210803129 3 2
+28 210803129 4 2
+28 210803129 5 2
+28 60497323 1 5
+28 60497323 2 5
+28 60497323 3 5
+28 60497323 4 5
+28 60497323 5 5
+28 188261423 1 9
+28 188261423 2 9
+28 188261423 3 9
+28 188261423 4 9
+28 188261423 5 9
+28 140541072 1 14
+28 140541072 2 14
+28 140541072 3 14
+28 140541072 4 14
+28 140541072 5 14
+28 33608837 1 17
+28 33608837 2 17
+28 33608837 3 17
+28 33608837 4 17
+28 33608837 5 17
+28 69772754 1 10
+28 69772754 2 10
+28 69772754 3 10
+28 69772754 4 10
+28 69772754 5 10
+28 231659097 1 3
+28 231659097 2 3
+28 231659097 3 3
+28 231659097 4 3
+28 231659097 5 3
+28 65708608 1 4
+28 65708608 2 4
+28 65708608 3 4
+28 65708608 4 4
+28 65708608 5 4
+28 27844939 1 5
+28 27844939 2 5
+28 27844939 3 5
+28 27844939 4 5
+28 27844939 5 5
+28 250016684 1 1
+28 250016684 2 1
+28 250016684 3 1
+28 250016684 4 1
+28 250016684 5 1
+28 27914189 1 10
+28 27914189 2 10
+28 27914189 3 10
+28 27914189 4 10
+28 27914189 5 10
+28 242637280 1 2
+28 242637280 2 2
+28 242637280 3 2
+28 242637280 4 2
+28 242637280 5 2
+28 100798268 1 4
+28 100798268 2 4
+28 100798268 3 4
+28 100798268 4 4
+28 100798268 5 4
+28 63664849 1 2
+28 63664849 2 2
+28 63664849 3 2
+28 63664849 4 2
+28 63664849 5 2
+28 186850612 1 9
+28 186850612 2 9
+28 186850612 3 9
+28 186850612 4 9
+28 186850612 5 9
+28 154249749 1 3
+28 154249749 2 3
+28 154249749 3 3
+28 154249749 4 3
+28 154249749 5 3
+28 90932767 1 8
+28 90932767 2 8
+28 90932767 3 8
+28 90932767 4 8
+28 90932767 5 8
+28 101133202 1 7
+28 101133202 2 7
+28 101133202 3 7
+28 101133202 4 7
+28 101133202 5 7
+28 161863951 1 13
+28 161863951 2 13
+28 161863951 3 13
+28 161863951 4 13
+28 161863951 5 13
+28 106351991 1 13
+28 106351991 2 13
+28 106351991 3 13
+28 106351991 4 13
+28 106351991 5 13
+28 164447437 1 6
+28 164447437 2 6
+28 164447437 3 6
+28 164447437 4 6
+28 164447437 5 6
+28 198321520 1 8
+28 198321520 2 8
+28 198321520 3 8
+28 198321520 4 8
+28 198321520 5 8
+28 66343474 1 5
+28 66343474 2 5
+28 66343474 3 5
+28 66343474 4 5
+28 66343474 5 5
+28 221986069 1 14
+28 221986069 2 14
+28 221986069 3 14
+28 221986069 4 14
+28 221986069 5 14
+28 19689396 1 0
+28 19689396 2 0
+28 19689396 3 0
+28 19689396 4 0
+28 19689396 5 0
+28 105945506 1 12
+28 105945506 2 12
+28 105945506 3 12
+28 105945506 4 12
+28 105945506 5 12
+28 153231939 1 9
+28 153231939 2 9
+28 153231939 3 9
+28 153231939 4 9
+28 153231939 5 9
+28 205884141 1 10
+28 205884141 2 10
+28 205884141 3 10
+28 205884141 4 10
+28 205884141 5 10
+28 101379925 1 0
+28 101379925 2 0
+28 101379925 3 0
+28 101379925 4 0
+28 101379925 5 0
+28 217838996 1 0
+28 217838996 2 0
+28 217838996 3 0
+28 217838996 4 0
+28 217838996 5 0
+28 146756671 1 10
+28 146756671 2 10
+28 146756671 3 10
+28 146756671 4 10
+28 146756671 5 10
+28 13896821 1 2
+28 13896821 2 2
+28 13896821 3 2
+28 13896821 4 2
+28 13896821 5 2
+28 262954695 1 8
+28 262954695 2 8
+28 262954695 3 8
+28 262954695 4 8
+28 262954695 5 8
+28 188329314 1 14
+28 188329314 2 14
+28 188329314 3 14
+28 188329314 4 14
+28 188329314 5 14
+28 166574838 1 12
+28 166574838 2 12
+28 166574838 3 12
+28 166574838 4 12
+28 166574838 5 12
+28 73291029 1 10
+28 73291029 2 10
+28 73291029 3 10
+28 73291029 4 10
+28 73291029 5 10
+28 60443185 1 17
+28 60443185 2 17
+28 60443185 3 17
+28 60443185 4 17
+28 60443185 5 17
+28 168418913 1 14
+28 168418913 2 14
+28 168418913 3 14
+28 168418913 4 14
+28 168418913 5 14
+28 106600330 1 4
+28 106600330 2 4
+28 106600330 3 4
+28 106600330 4 4
+28 106600330 5 4
+28 224100522 1 13
+28 224100522 2 13
+28 224100522 3 13
+28 224100522 4 13
+28 224100522 5 13
+28 50445651 1 13
+28 50445651 2 13
+28 50445651 3 13
+28 50445651 4 13
+28 50445651 5 13
+28 49791383 1 0
+28 49791383 2 0
+28 49791383 3 0
+28 49791383 4 0
+28 49791383 5 0
+28 56004596 1 7
+28 56004596 2 7
+28 56004596 3 7
+28 56004596 4 7
+28 56004596 5 7
+28 163008005 1 9
+28 163008005 2 9
+28 163008005 3 9
+28 163008005 4 9
+28 163008005 5 9
+28 130294270 1 8
+28 130294270 2 8
+28 130294270 3 8
+28 130294270 4 8
+28 130294270 5 8
+28 79031870 1 7
+28 79031870 2 7
+28 79031870 3 7
+28 79031870 4 7
+28 79031870 5 7
+28 8779135 1 7
+28 8779135 2 7
+28 8779135 3 7
+28 8779135 4 7
+28 8779135 5 7
+28 132122986 1 3
+28 132122986 2 3
+28 132122986 3 3
+28 132122986 4 3
+28 132122986 5 3
+28 106262167 1 3
+28 106262167 2 3
+28 106262167 3 3
+28 106262167 4 3
+28 106262167 5 3
+28 84962373 1 14
+28 84962373 2 14
+28 84962373 3 14
+28 84962373 4 14
+28 84962373 5 14
+28 149117771 1 2
+28 149117771 2 2
+28 149117771 3 2
+28 149117771 4 2
+28 149117771 5 2
+28 179783442 1 15
+28 179783442 2 15
+28 179783442 3 15
+28 179783442 4 15
+28 179783442 5 15
+29 335271491 1 6
+29 335271491 2 6
+29 335271491 3 6
+29 335271491 4 6
+29 335271491 5 6
+29 10720791 1 17
+29 10720791 2 17
+29 10720791 3 17
+29 10720791 4 17
+29 10720791 5 17
+29 500040308 1 0
+29 500040308 2 0
+29 500040308 3 0
+29 500040308 4 0
+29 500040308 5 0
+29 510755966 1 8
+29 510755966 2 8
+29 510755966 3 8
+29 510755966 4 8
+29 510755966 5 8
+29 227186933 1 15
+29 227186933 2 15
+29 227186933 3 15
+29 227186933 4 15
+29 227186933 5 15
+29 422662843 1 13
+29 422662843 2 13
+29 422662843 3 13
+29 422662843 4 13
+29 422662843 5 13
+29 81866932 1 3
+29 81866932 2 3
+29 81866932 3 3
+29 81866932 4 3
+29 81866932 5 3
+29 470195498 1 9
+29 470195498 2 9
+29 470195498 3 9
+29 470195498 4 9
+29 470195498 5 9
+29 505281812 1 6
+29 505281812 2 6
+29 505281812 3 6
+29 505281812 4 6
+29 505281812 5 6
+29 42328055 1 17
+29 42328055 2 17
+29 42328055 3 17
+29 42328055 4 17
+29 42328055 5 17
+29 510604597 1 4
+29 510604597 2 4
+29 510604597 3 4
+29 510604597 4 4
+29 510604597 5 4
+29 380926471 1 10
+29 380926471 2 10
+29 380926471 3 10
+29 380926471 4 10
+29 380926471 5 10
+29 159591288 1 5
+29 159591288 2 5
+29 159591288 3 5
+29 159591288 4 5
+29 159591288 5 5
+29 189495832 1 13
+29 189495832 2 13
+29 189495832 3 13
+29 189495832 4 13
+29 189495832 5 13
+29 7461185 1 1
+29 7461185 2 1
+29 7461185 3 1
+29 7461185 4 1
+29 7461185 5 1
+29 41392678 1 15
+29 41392678 2 15
+29 41392678 3 15
+29 41392678 4 15
+29 41392678 5 15
+29 466412287 1 7
+29 466412287 2 7
+29 466412287 3 7
+29 466412287 4 7
+29 466412287 5 7
+29 269683984 1 10
+29 269683984 2 10
+29 269683984 3 10
+29 269683984 4 10
+29 269683984 5 10
+29 81614953 1 14
+29 81614953 2 14
+29 81614953 3 14
+29 81614953 4 14
+29 81614953 5 14
+29 117179003 1 4
+29 117179003 2 4
+29 117179003 3 4
+29 117179003 4 4
+29 117179003 5 4
+29 348566793 1 17
+29 348566793 2 17
+29 348566793 3 17
+29 348566793 4 17
+29 348566793 5 17
+29 502596854 1 4
+29 502596854 2 4
+29 502596854 3 4
+29 502596854 4 4
+29 502596854 5 4
+29 364569853 1 17
+29 364569853 2 17
+29 364569853 3 17
+29 364569853 4 17
+29 364569853 5 17
+29 262837855 1 5
+29 262837855 2 5
+29 262837855 3 5
+29 262837855 4 5
+29 262837855 5 5
+29 316887548 1 10
+29 316887548 2 10
+29 316887548 3 10
+29 316887548 4 10
+29 316887548 5 10
+29 223063684 1 4
+29 223063684 2 4
+29 223063684 3 4
+29 223063684 4 4
+29 223063684 5 4
+29 459226263 1 15
+29 459226263 2 15
+29 459226263 3 15
+29 459226263 4 15
+29 459226263 5 15
+29 299433996 1 5
+29 299433996 2 5
+29 299433996 3 5
+29 299433996 4 5
+29 299433996 5 5
+29 200795585 1 15
+29 200795585 2 15
+29 200795585 3 15
+29 200795585 4 15
+29 200795585 5 15
+29 136914840 1 13
+29 136914840 2 13
+29 136914840 3 13
+29 136914840 4 13
+29 136914840 5 13
+29 237980817 1 17
+29 237980817 2 17
+29 237980817 3 17
+29 237980817 4 17
+29 237980817 5 17
+29 350103844 1 14
+29 350103844 2 14
+29 350103844 3 14
+29 350103844 4 14
+29 350103844 5 14
+29 441877573 1 3
+29 441877573 2 3
+29 441877573 3 3
+29 441877573 4 3
+29 441877573 5 3
+29 40558515 1 10
+29 40558515 2 10
+29 40558515 3 10
+29 40558515 4 10
+29 40558515 5 10
+29 161801865 1 7
+29 161801865 2 7
+29 161801865 3 7
+29 161801865 4 7
+29 161801865 5 7
+29 504185643 1 5
+29 504185643 2 5
+29 504185643 3 5
+29 504185643 4 5
+29 504185643 5 5
+29 85566969 1 13
+29 85566969 2 13
+29 85566969 3 13
+29 85566969 4 13
+29 85566969 5 13
+29 59549821 1 0
+29 59549821 2 0
+29 59549821 3 0
+29 59549821 4 0
+29 59549821 5 0
+29 42304740 1 6
+29 42304740 2 6
+29 42304740 3 6
+29 42304740 4 6
+29 42304740 5 6
+29 14245896 1 6
+29 14245896 2 6
+29 14245896 3 6
+29 14245896 4 6
+29 14245896 5 6
+29 313701459 1 12
+29 313701459 2 12
+29 313701459 3 12
+29 313701459 4 12
+29 313701459 5 12
+29 77420095 1 6
+29 77420095 2 6
+29 77420095 3 6
+29 77420095 4 6
+29 77420095 5 6
+29 243081033 1 1
+29 243081033 2 1
+29 243081033 3 1
+29 243081033 4 1
+29 243081033 5 1
+29 430152328 1 10
+29 430152328 2 10
+29 430152328 3 10
+29 430152328 4 10
+29 430152328 5 10
+29 84780619 1 17
+29 84780619 2 17
+29 84780619 3 17
+29 84780619 4 17
+29 84780619 5 17
+29 251064423 1 5
+29 251064423 2 5
+29 251064423 3 5
+29 251064423 4 5
+29 251064423 5 5
+29 529469218 1 13
+29 529469218 2 13
+29 529469218 3 13
+29 529469218 4 13
+29 529469218 5 13
+29 133549787 1 12
+29 133549787 2 12
+29 133549787 3 12
+29 133549787 4 12
+29 133549787 5 12
+29 383495391 1 2
+29 383495391 2 2
+29 383495391 3 2
+29 383495391 4 2
+29 383495391 5 2
+29 446460424 1 1
+29 446460424 2 1
+29 446460424 3 1
+29 446460424 4 1
+29 446460424 5 1
+29 302973982 1 15
+29 302973982 2 15
+29 302973982 3 15
+29 302973982 4 15
+29 302973982 5 15
+29 321643285 1 2
+29 321643285 2 2
+29 321643285 3 2
+29 321643285 4 2
+29 321643285 5 2
+29 299298703 1 17
+29 299298703 2 17
+29 299298703 3 17
+29 299298703 4 17
+29 299298703 5 17
+29 90118743 1 13
+29 90118743 2 13
+29 90118743 3 13
+29 90118743 4 13
+29 90118743 5 13
+29 269748402 1 5
+29 269748402 2 5
+29 269748402 3 5
+29 269748402 4 5
+29 269748402 5 5
+29 47030190 1 6
+29 47030190 2 6
+29 47030190 3 6
+29 47030190 4 6
+29 47030190 5 6
+29 504453345 1 14
+29 504453345 2 14
+29 504453345 3 14
+29 504453345 4 14
+29 504453345 5 14
+29 506285359 1 10
+29 506285359 2 10
+29 506285359 3 10
+29 506285359 4 10
+29 506285359 5 10
+29 429364883 1 0
+29 429364883 2 0
+29 429364883 3 0
+29 429364883 4 0
+29 429364883 5 0
+29 437983235 1 3
+29 437983235 2 3
+29 437983235 3 3
+29 437983235 4 3
+29 437983235 5 3
+29 446722782 1 1
+29 446722782 2 1
+29 446722782 3 1
+29 446722782 4 1
+29 446722782 5 1
+29 170722190 1 5
+29 170722190 2 5
+29 170722190 3 5
+29 170722190 4 5
+29 170722190 5 5
+29 347257661 1 1
+29 347257661 2 1
+29 347257661 3 1
+29 347257661 4 1
+29 347257661 5 1
+29 344826579 1 3
+29 344826579 2 3
+29 344826579 3 3
+29 344826579 4 3
+29 344826579 5 3
+30 213793736 1 17
+30 213793736 2 17
+30 213793736 3 17
+30 213793736 4 17
+30 213793736 5 17
+30 841563124 1 8
+30 841563124 2 8
+30 841563124 3 8
+30 841563124 4 8
+30 841563124 5 8
+30 497541093 1 0
+30 497541093 2 0
+30 497541093 3 0
+30 497541093 4 0
+30 497541093 5 0
+30 886071695 1 4
+30 886071695 2 4
+30 886071695 3 4
+30 886071695 4 4
+30 886071695 5 4
+30 442450336 1 15
+30 442450336 2 15
+30 442450336 3 15
+30 442450336 4 15
+30 442450336 5 15
+30 359840809 1 1
+30 359840809 2 1
+30 359840809 3 1
+30 359840809 4 1
+30 359840809 5 1
+30 237523472 1 7
+30 237523472 2 7
+30 237523472 3 7
+30 237523472 4 7
+30 237523472 5 7
+30 841255244 1 5
+30 841255244 2 5
+30 841255244 3 5
+30 841255244 4 5
+30 841255244 5 5
+30 254748983 1 7
+30 254748983 2 7
+30 254748983 3 7
+30 254748983 4 7
+30 254748983 5 7
+30 888089982 1 9
+30 888089982 2 9
+30 888089982 3 9
+30 888089982 4 9
+30 888089982 5 9
+30 514507124 1 17
+30 514507124 2 17
+30 514507124 3 17
+30 514507124 4 17
+30 514507124 5 17
+30 954375894 1 0
+30 954375894 2 0
+30 954375894 3 0
+30 954375894 4 0
+30 954375894 5 0
+30 313226812 1 1
+30 313226812 2 1
+30 313226812 3 1
+30 313226812 4 1
+30 313226812 5 1
+30 339371217 1 15
+30 339371217 2 15
+30 339371217 3 15
+30 339371217 4 15
+30 339371217 5 15
+30 818297353 1 4
+30 818297353 2 4
+30 818297353 3 4
+30 818297353 4 4
+30 818297353 5 4
+30 70402405 1 5
+30 70402405 2 5
+30 70402405 3 5
+30 70402405 4 5
+30 70402405 5 5
+30 778614673 1 10
+30 778614673 2 10
+30 778614673 3 10
+30 778614673 4 10
+30 778614673 5 10
+30 475256662 1 14
+30 475256662 2 14
+30 475256662 3 14
+30 475256662 4 14
+30 475256662 5 14
+30 263311931 1 2
+30 263311931 2 2
+30 263311931 3 2
+30 263311931 4 2
+30 263311931 5 2
+30 499638729 1 3
+30 499638729 2 3
+30 499638729 3 3
+30 499638729 4 3
+30 499638729 5 3
+30 191707598 1 9
+30 191707598 2 9
+30 191707598 3 9
+30 191707598 4 9
+30 191707598 5 9
+30 13291798 1 17
+30 13291798 2 17
+30 13291798 3 17
+30 13291798 4 17
+30 13291798 5 17
+30 428344683 1 2
+30 428344683 2 2
+30 428344683 3 2
+30 428344683 4 2
+30 428344683 5 2
+30 470671586 1 14
+30 470671586 2 14
+30 470671586 3 14
+30 470671586 4 14
+30 470671586 5 14
+30 1010796989 1 7
+30 1010796989 2 7
+30 1010796989 3 7
+30 1010796989 4 7
+30 1010796989 5 7
+30 550173547 1 5
+30 550173547 2 5
+30 550173547 3 5
+30 550173547 4 5
+30 550173547 5 5
+30 984276590 1 3
+30 984276590 2 3
+30 984276590 3 3
+30 984276590 4 3
+30 984276590 5 3
+30 400752165 1 15
+30 400752165 2 15
+30 400752165 3 15
+30 400752165 4 15
+30 400752165 5 15
+30 676513500 1 0
+30 676513500 2 0
+30 676513500 3 0
+30 676513500 4 0
+30 676513500 5 0
+30 29569926 1 13
+30 29569926 2 13
+30 29569926 3 13
+30 29569926 4 13
+30 29569926 5 13
+30 814936588 1 2
+30 814936588 2 2
+30 814936588 3 2
+30 814936588 4 2
+30 814936588 5 2
+30 424154654 1 1
+30 424154654 2 1
+30 424154654 3 1
+30 424154654 4 1
+30 424154654 5 1
+30 414893534 1 1
+30 414893534 2 1
+30 414893534 3 1
+30 414893534 4 1
+30 414893534 5 1
+30 1050718441 1 6
+30 1050718441 2 6
+30 1050718441 3 6
+30 1050718441 4 6
+30 1050718441 5 6
+30 680733058 1 8
+30 680733058 2 8
+30 680733058 3 8
+30 680733058 4 8
+30 680733058 5 8
+30 194457832 1 13
+30 194457832 2 13
+30 194457832 3 13
+30 194457832 4 13
+30 194457832 5 13
+30 961676074 1 3
+30 961676074 2 3
+30 961676074 3 3
+30 961676074 4 3
+30 961676074 5 3
+30 735607789 1 15
+30 735607789 2 15
+30 735607789 3 15
+30 735607789 4 15
+30 735607789 5 15
+30 375086337 1 6
+30 375086337 2 6
+30 375086337 3 6
+30 375086337 4 6
+30 375086337 5 6
+30 52289719 1 0
+30 52289719 2 0
+30 52289719 3 0
+30 52289719 4 0
+30 52289719 5 0
+30 482043226 1 1
+30 482043226 2 1
+30 482043226 3 1
+30 482043226 4 1
+30 482043226 5 1
+30 1035547710 1 4
+30 1035547710 2 4
+30 1035547710 3 4
+30 1035547710 4 4
+30 1035547710 5 4
+30 222543404 1 10
+30 222543404 2 10
+30 222543404 3 10
+30 222543404 4 10
+30 222543404 5 10
+30 1060433998 1 2
+30 1060433998 2 2
+30 1060433998 3 2
+30 1060433998 4 2
+30 1060433998 5 2
+30 887738302 1 7
+30 887738302 2 7
+30 887738302 3 7
+30 887738302 4 7
+30 887738302 5 7
+30 868165466 1 0
+30 868165466 2 0
+30 868165466 3 0
+30 868165466 4 0
+30 868165466 5 0
+30 1051398814 1 8
+30 1051398814 2 8
+30 1051398814 3 8
+30 1051398814 4 8
+30 1051398814 5 8
+30 489644425 1 6
+30 489644425 2 6
+30 489644425 3 6
+30 489644425 4 6
+30 489644425 5 6
+30 1024951511 1 15
+30 1024951511 2 15
+30 1024951511 3 15
+30 1024951511 4 15
+30 1024951511 5 15
+30 686077717 1 15
+30 686077717 2 15
+30 686077717 3 15
+30 686077717 4 15
+30 686077717 5 15
+30 1056030306 1 0
+30 1056030306 2 0
+30 1056030306 3 0
+30 1056030306 4 0
+30 1056030306 5 0
+30 565885909 1 8
+30 565885909 2 8
+30 565885909 3 8
+30 565885909 4 8
+30 565885909 5 8
+30 89610460 1 9
+30 89610460 2 9
+30 89610460 3 9
+30 89610460 4 9
+30 89610460 5 9
+30 774443031 1 2
+30 774443031 2 2
+30 774443031 3 2
+30 774443031 4 2
+30 774443031 5 2
+30 433823353 1 15
+30 433823353 2 15
+30 433823353 3 15
+30 433823353 4 15
+30 433823353 5 15
+30 394963635 1 3
+30 394963635 2 3
+30 394963635 3 3
+30 394963635 4 3
+30 394963635 5 3
+30 724153400 1 14
+30 724153400 2 14
+30 724153400 3 14
+30 724153400 4 14
+30 724153400 5 14
+30 29831260 1 4
+30 29831260 2 4
+30 29831260 3 4
+30 29831260 4 4
+30 29831260 5 4
+30 241349464 1 9
+30 241349464 2 9
+30 241349464 3 9
+30 241349464 4 9
+30 241349464 5 9
+30 57273401 1 3
+30 57273401 2 3
+30 57273401 3 3
+30 57273401 4 3
+30 57273401 5 3
+30 230647305 1 2
+30 230647305 2 2
+30 230647305 3 2
+30 230647305 4 2
+30 230647305 5 2
+30 181878195 1 15
+30 181878195 2 15
+30 181878195 3 15
+30 181878195 4 15
+30 181878195 5 15
+30 21273447 1 12
+30 21273447 2 12
+30 21273447 3 12
+30 21273447 4 12
+30 21273447 5 12
+30 386568080 1 6
+30 386568080 2 6
+30 386568080 3 6
+30 386568080 4 6
+30 386568080 5 6
+31 433243292 1 4
+31 433243292 2 4
+31 433243292 3 4
+31 433243292 4 4
+31 433243292 5 4
+31 743572650 1 9
+31 743572650 2 9
+31 743572650 3 9
+31 743572650 4 9
+31 743572650 5 9
+31 1751072959 1 3
+31 1751072959 2 3
+31 1751072959 3 3
+31 1751072959 4 3
+31 1751072959 5 3
+31 582009481 1 13
+31 582009481 2 13
+31 582009481 3 13
+31 582009481 4 13
+31 582009481 5 13
+31 1086523751 1 5
+31 1086523751 2 5
+31 1086523751 3 5
+31 1086523751 4 5
+31 1086523751 5 5
+31 1633480282 1 13
+31 1633480282 2 13
+31 1633480282 3 13
+31 1633480282 4 13
+31 1633480282 5 13
+31 543551900 1 8
+31 543551900 2 8
+31 543551900 3 8
+31 543551900 4 8
+31 543551900 5 8
+31 359654721 1 14
+31 359654721 2 14
+31 359654721 3 14
+31 359654721 4 14
+31 359654721 5 14
+31 517216897 1 8
+31 517216897 2 8
+31 517216897 3 8
+31 517216897 4 8
+31 517216897 5 8
+31 1321997222 1 7
+31 1321997222 2 7
+31 1321997222 3 7
+31 1321997222 4 7
+31 1321997222 5 7
+31 1765905076 1 10
+31 1765905076 2 10
+31 1765905076 3 10
+31 1765905076 4 10
+31 1765905076 5 10
+31 1658010939 1 2
+31 1658010939 2 2
+31 1658010939 3 2
+31 1658010939 4 2
+31 1658010939 5 2
+31 798885882 1 4
+31 798885882 2 4
+31 798885882 3 4
+31 798885882 4 4
+31 798885882 5 4
+31 1542111550 1 6
+31 1542111550 2 6
+31 1542111550 3 6
+31 1542111550 4 6
+31 1542111550 5 6
+31 1979674396 1 15
+31 1979674396 2 15
+31 1979674396 3 15
+31 1979674396 4 15
+31 1979674396 5 15
+31 1313431291 1 14
+31 1313431291 2 14
+31 1313431291 3 14
+31 1313431291 4 14
+31 1313431291 5 14
+31 1748289035 1 10
+31 1748289035 2 10
+31 1748289035 3 10
+31 1748289035 4 10
+31 1748289035 5 10
+31 2017345172 1 12
+31 2017345172 2 12
+31 2017345172 3 12
+31 2017345172 4 12
+31 2017345172 5 12
+31 1992315978 1 9
+31 1992315978 2 9
+31 1992315978 3 9
+31 1992315978 4 9
+31 1992315978 5 9
+31 1624850948 1 17
+31 1624850948 2 17
+31 1624850948 3 17
+31 1624850948 4 17
+31 1624850948 5 17
+31 780864908 1 15
+31 780864908 2 15
+31 780864908 3 15
+31 780864908 4 15
+31 780864908 5 15
+31 534307425 1 17
+31 534307425 2 17
+31 534307425 3 17
+31 534307425 4 17
+31 534307425 5 17
+31 1301871260 1 7
+31 1301871260 2 7
+31 1301871260 3 7
+31 1301871260 4 7
+31 1301871260 5 7
+31 222436705 1 6
+31 222436705 2 6
+31 222436705 3 6
+31 222436705 4 6
+31 222436705 5 6
+31 421579900 1 4
+31 421579900 2 4
+31 421579900 3 4
+31 421579900 4 4
+31 421579900 5 4
+31 2051749662 1 15
+31 2051749662 2 15
+31 2051749662 3 15
+31 2051749662 4 15
+31 2051749662 5 15
+31 1525087697 1 1
+31 1525087697 2 1
+31 1525087697 3 1
+31 1525087697 4 1
+31 1525087697 5 1
+31 9065501 1 7
+31 9065501 2 7
+31 9065501 3 7
+31 9065501 4 7
+31 9065501 5 7
+31 1054811774 1 14
+31 1054811774 2 14
+31 1054811774 3 14
+31 1054811774 4 14
+31 1054811774 5 14
+31 1675964300 1 5
+31 1675964300 2 5
+31 1675964300 3 5
+31 1675964300 4 5
+31 1675964300 5 5
+31 85747085 1 3
+31 85747085 2 3
+31 85747085 3 3
+31 85747085 4 3
+31 85747085 5 3
+31 2010083787 1 12
+31 2010083787 2 12
+31 2010083787 3 12
+31 2010083787 4 12
+31 2010083787 5 12
+31 960759126 1 1
+31 960759126 2 1
+31 960759126 3 1
+31 960759126 4 1
+31 960759126 5 1
+31 892955437 1 7
+31 892955437 2 7
+31 892955437 3 7
+31 892955437 4 7
+31 892955437 5 7
+31 1581497818 1 13
+31 1581497818 2 13
+31 1581497818 3 13
+31 1581497818 4 13
+31 1581497818 5 13
+31 2087270142 1 7
+31 2087270142 2 7
+31 2087270142 3 7
+31 2087270142 4 7
+31 2087270142 5 7
+31 1564424559 1 4
+31 1564424559 2 4
+31 1564424559 3 4
+31 1564424559 4 4
+31 1564424559 5 4
+31 1762953928 1 7
+31 1762953928 2 7
+31 1762953928 3 7
+31 1762953928 4 7
+31 1762953928 5 7
+31 264159138 1 14
+31 264159138 2 14
+31 264159138 3 14
+31 264159138 4 14
+31 264159138 5 14
+31 934393298 1 13
+31 934393298 2 13
+31 934393298 3 13
+31 934393298 4 13
+31 934393298 5 13
+31 425929304 1 8
+31 425929304 2 8
+31 425929304 3 8
+31 425929304 4 8
+31 425929304 5 8
+31 1431999721 1 9
+31 1431999721 2 9
+31 1431999721 3 9
+31 1431999721 4 9
+31 1431999721 5 9
+31 50432310 1 0
+31 50432310 2 0
+31 50432310 3 0
+31 50432310 4 0
+31 50432310 5 0
+31 671383138 1 0
+31 671383138 2 0
+31 671383138 3 0
+31 671383138 4 0
+31 671383138 5 0
+31 1514870594 1 15
+31 1514870594 2 15
+31 1514870594 3 15
+31 1514870594 4 15
+31 1514870594 5 15
+31 125594206 1 12
+31 125594206 2 12
+31 125594206 3 12
+31 125594206 4 12
+31 125594206 5 12
+31 340551370 1 4
+31 340551370 2 4
+31 340551370 3 4
+31 340551370 4 4
+31 340551370 5 4
+31 1623645007 1 15
+31 1623645007 2 15
+31 1623645007 3 15
+31 1623645007 4 15
+31 1623645007 5 15
+31 1348003716 1 4
+31 1348003716 2 4
+31 1348003716 3 4
+31 1348003716 4 4
+31 1348003716 5 4
+31 2037861051 1 7
+31 2037861051 2 7
+31 2037861051 3 7
+31 2037861051 4 7
+31 2037861051 5 7
+31 2057710326 1 5
+31 2057710326 2 5
+31 2057710326 3 5
+31 2057710326 4 5
+31 2057710326 5 5
+31 663428672 1 13
+31 663428672 2 13
+31 663428672 3 13
+31 663428672 4 13
+31 663428672 5 13
+31 1949076248 1 8
+31 1949076248 2 8
+31 1949076248 3 8
+31 1949076248 4 8
+31 1949076248 5 8
+31 1083205847 1 8
+31 1083205847 2 8
+31 1083205847 3 8
+31 1083205847 4 8
+31 1083205847 5 8
+31 1989744438 1 0
+31 1989744438 2 0
+31 1989744438 3 0
+31 1989744438 4 0
+31 1989744438 5 0
+31 815856732 1 9
+31 815856732 2 9
+31 815856732 3 9
+31 815856732 4 9
+31 815856732 5 9
+31 829877019 1 6
+31 829877019 2 6
+31 829877019 3 6
+31 829877019 4 6
+31 829877019 5 6
+31 188649293 1 10
+31 188649293 2 10
+31 188649293 3 10
+31 188649293 4 10
+31 188649293 5 10
+31 1198806123 1 1
+31 1198806123 2 1
+31 1198806123 3 1
+31 1198806123 4 1
+31 1198806123 5 1
+31 1973746385 1 4
+31 1973746385 2 4
+31 1973746385 3 4
+31 1973746385 4 4
+31 1973746385 5 4
+31 839543376 1 6
+31 839543376 2 6
+31 839543376 3 6
+31 839543376 4 6
+31 839543376 5 6
+31 1072944380 1 14
+31 1072944380 2 14
+31 1072944380 3 14
+31 1072944380 4 14
+31 1072944380 5 14
+31 1561590617 1 17
+31 1561590617 2 17
+31 1561590617 3 17
+31 1561590617 4 17
+31 1561590617 5 17
+31 551611217 1 10
+31 551611217 2 10
+31 551611217 3 10
+31 551611217 4 10
+31 551611217 5 10
+32 1036684082 1 9
+32 1036684082 2 9
+32 1036684082 3 9
+32 1036684082 4 9
+32 1036684082 5 9
+32 2486634245 1 10
+32 2486634245 2 10
+32 2486634245 3 10
+32 2486634245 4 10
+32 2486634245 5 10
+32 1960853583 1 14
+32 1960853583 2 14
+32 1960853583 3 14
+32 1960853583 4 14
+32 1960853583 5 14
+32 2216609468 1 3
+32 2216609468 2 3
+32 2216609468 3 3
+32 2216609468 4 3
+32 2216609468 5 3
+32 221178161 1 7
+32 221178161 2 7
+32 221178161 3 7
+32 221178161 4 7
+32 221178161 5 7
+32 439758692 1 3
+32 439758692 2 3
+32 439758692 3 3
+32 439758692 4 3
+32 439758692 5 3
+32 1129185496 1 12
+32 1129185496 2 12
+32 1129185496 3 12
+32 1129185496 4 12
+32 1129185496 5 12
+32 1867788184 1 4
+32 1867788184 2 4
+32 1867788184 3 4
+32 1867788184 4 4
+32 1867788184 5 4
+32 564853289 1 8
+32 564853289 2 8
+32 564853289 3 8
+32 564853289 4 8
+32 564853289 5 8
+32 2344179581 1 5
+32 2344179581 2 5
+32 2344179581 3 5
+32 2344179581 4 5
+32 2344179581 5 5
+32 2970472705 1 0
+32 2970472705 2 0
+32 2970472705 3 0
+32 2970472705 4 0
+32 2970472705 5 0
+32 4070187504 1 9
+32 4070187504 2 9
+32 4070187504 3 9
+32 4070187504 4 9
+32 4070187504 5 9
+32 2662144140 1 9
+32 2662144140 2 9
+32 2662144140 3 9
+32 2662144140 4 9
+32 2662144140 5 9
+32 4167572734 1 10
+32 4167572734 2 10
+32 4167572734 3 10
+32 4167572734 4 10
+32 4167572734 5 10
+32 927210200 1 6
+32 927210200 2 6
+32 927210200 3 6
+32 927210200 4 6
+32 927210200 5 6
+32 2208343448 1 5
+32 2208343448 2 5
+32 2208343448 3 5
+32 2208343448 4 5
+32 2208343448 5 5
+32 2192760228 1 3
+32 2192760228 2 3
+32 2192760228 3 3
+32 2192760228 4 3
+32 2192760228 5 3
+32 2166303367 1 7
+32 2166303367 2 7
+32 2166303367 3 7
+32 2166303367 4 7
+32 2166303367 5 7
+32 3688439934 1 6
+32 3688439934 2 6
+32 3688439934 3 6
+32 3688439934 4 6
+32 3688439934 5 6
+32 308030109 1 5
+32 308030109 2 5
+32 308030109 3 5
+32 308030109 4 5
+32 308030109 5 5
+32 1104848908 1 1
+32 1104848908 2 1
+32 1104848908 3 1
+32 1104848908 4 1
+32 1104848908 5 1
+32 3705758252 1 12
+32 3705758252 2 12
+32 3705758252 3 12
+32 3705758252 4 12
+32 3705758252 5 12
+32 336358057 1 2
+32 336358057 2 2
+32 336358057 3 2
+32 336358057 4 2
+32 336358057 5 2
+32 701422524 1 7
+32 701422524 2 7
+32 701422524 3 7
+32 701422524 4 7
+32 701422524 5 7
+32 95384115 1 9
+32 95384115 2 9
+32 95384115 3 9
+32 95384115 4 9
+32 95384115 5 9
+32 3922974711 1 14
+32 3922974711 2 14
+32 3922974711 3 14
+32 3922974711 4 14
+32 3922974711 5 14
+32 60262178 1 7
+32 60262178 2 7
+32 60262178 3 7
+32 60262178 4 7
+32 60262178 5 7
+32 2696528104 1 5
+32 2696528104 2 5
+32 2696528104 3 5
+32 2696528104 4 5
+32 2696528104 5 5
+32 19462365 1 15
+32 19462365 2 15
+32 19462365 3 15
+32 19462365 4 15
+32 19462365 5 15
+32 2463013988 1 12
+32 2463013988 2 12
+32 2463013988 3 12
+32 2463013988 4 12
+32 2463013988 5 12
+32 1023022920 1 3
+32 1023022920 2 3
+32 1023022920 3 3
+32 1023022920 4 3
+32 1023022920 5 3
+32 3781145032 1 13
+32 3781145032 2 13
+32 3781145032 3 13
+32 3781145032 4 13
+32 3781145032 5 13
+32 1830433185 1 10
+32 1830433185 2 10
+32 1830433185 3 10
+32 1830433185 4 10
+32 1830433185 5 10
+32 424433380 1 8
+32 424433380 2 8
+32 424433380 3 8
+32 424433380 4 8
+32 424433380 5 8
+32 1623797388 1 10
+32 1623797388 2 10
+32 1623797388 3 10
+32 1623797388 4 10
+32 1623797388 5 10
+32 3401848886 1 14
+32 3401848886 2 14
+32 3401848886 3 14
+32 3401848886 4 14
+32 3401848886 5 14
+32 1317540203 1 5
+32 1317540203 2 5
+32 1317540203 3 5
+32 1317540203 4 5
+32 1317540203 5 5
+32 1120055386 1 1
+32 1120055386 2 1
+32 1120055386 3 1
+32 1120055386 4 1
+32 1120055386 5 1
+32 454820083 1 0
+32 454820083 2 0
+32 454820083 3 0
+32 454820083 4 0
+32 454820083 5 0
+32 1359971009 1 14
+32 1359971009 2 14
+32 1359971009 3 14
+32 1359971009 4 14
+32 1359971009 5 14
+32 497197820 1 15
+32 497197820 2 15
+32 497197820 3 15
+32 497197820 4 15
+32 497197820 5 15
+32 4289564065 1 15
+32 4289564065 2 15
+32 4289564065 3 15
+32 4289564065 4 15
+32 4289564065 5 15
+32 124772759 1 17
+32 124772759 2 17
+32 124772759 3 17
+32 124772759 4 17
+32 124772759 5 17
+32 1308886828 1 1
+32 1308886828 2 1
+32 1308886828 3 1
+32 1308886828 4 1
+32 1308886828 5 1
+32 3243928933 1 10
+32 3243928933 2 10
+32 3243928933 3 10
+32 3243928933 4 10
+32 3243928933 5 10
+32 3788970499 1 1
+32 3788970499 2 1
+32 3788970499 3 1
+32 3788970499 4 1
+32 3788970499 5 1
+32 4103967014 1 0
+32 4103967014 2 0
+32 4103967014 3 0
+32 4103967014 4 0
+32 4103967014 5 0
+32 1705735405 1 10
+32 1705735405 2 10
+32 1705735405 3 10
+32 1705735405 4 10
+32 1705735405 5 10
+32 416033424 1 2
+32 416033424 2 2
+32 416033424 3 2
+32 416033424 4 2
+32 416033424 5 2
+32 514236867 1 4
+32 514236867 2 4
+32 514236867 3 4
+32 514236867 4 4
+32 514236867 5 4
+32 3686390881 1 4
+32 3686390881 2 4
+32 3686390881 3 4
+32 3686390881 4 4
+32 3686390881 5 4
+32 2125027247 1 12
+32 2125027247 2 12
+32 2125027247 3 12
+32 2125027247 4 12
+32 2125027247 5 12
+32 2029833655 1 8
+32 2029833655 2 8
+32 2029833655 3 8
+32 2029833655 4 8
+32 2029833655 5 8
+32 3917495445 1 7
+32 3917495445 2 7
+32 3917495445 3 7
+32 3917495445 4 7
+32 3917495445 5 7
+32 2650507935 1 5
+32 2650507935 2 5
+32 2650507935 3 5
+32 2650507935 4 5
+32 2650507935 5 5
+32 282773968 1 13
+32 282773968 2 13
+32 282773968 3 13
+32 282773968 4 13
+32 282773968 5 13
+32 446683627 1 10
+32 446683627 2 10
+32 446683627 3 10
+32 446683627 4 10
+32 446683627 5 10
+32 2843691041 1 15
+32 2843691041 2 15
+32 2843691041 3 15
+32 2843691041 4 15
+32 2843691041 5 15
+32 1191222343 1 8
+32 1191222343 2 8
+32 1191222343 3 8
+32 1191222343 4 8
+32 1191222343 5 8
+32 2016286435 1 10
+32 2016286435 2 10
+32 2016286435 3 10
+32 2016286435 4 10
+32 2016286435 5 10
+32 1893861518 1 5
+32 1893861518 2 5
+32 1893861518 3 5
+32 1893861518 4 5
+32 1893861518 5 5
+32 3977622147 1 12
+32 3977622147 2 12
+32 3977622147 3 12
+32 3977622147 4 12
+32 3977622147 5 12
+32 571267417 1 15
+32 571267417 2 15
+32 571267417 3 15
+32 571267417 4 15
+32 571267417 5 15
+32 2363239984 1 13
+32 2363239984 2 13
+32 2363239984 3 13
+32 2363239984 4 13
+32 2363239984 5 13
diff --git a/vdslib/src/tests/distribution/testdata/java_depth3.state b/vdslib/src/tests/distribution/testdata/java_depth3.state
new file mode 100644
index 00000000000..f0bf7f91656
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/java_depth3.state
@@ -0,0 +1 @@
+distributor:20 storage:20 \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/java_retired.cfg b/vdslib/src/tests/distribution/testdata/java_retired.cfg
new file mode 100644
index 00000000000..fc0e597013d
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/java_retired.cfg
@@ -0,0 +1,46 @@
+redundancy 5
+group[7]
+group[0].partitions "*|*"
+group[0].index "invalid"
+group[0].name "invalid"
+group[0].nodes[0]
+group[1].partitions "1|*"
+group[1].index "0"
+group[1].name "switch0"
+group[1].nodes[0]
+group[2].partitions ""
+group[2].index "0.0"
+group[2].name "rack0"
+group[2].nodes[4]
+group[2].nodes[0].index 0
+group[2].nodes[1].index 1
+group[2].nodes[2].index 2
+group[2].nodes[3].index 3
+group[3].partitions ""
+group[3].index "0.1"
+group[3].name "rack1"
+group[3].nodes[4]
+group[3].nodes[0].index 8
+group[3].nodes[1].index 9
+group[3].nodes[2].index 14
+group[3].nodes[3].index 15
+group[4].partitions "*"
+group[4].index "1"
+group[4].name "switch1"
+group[4].nodes[0]
+group[5].partitions ""
+group[5].index "1.0"
+group[5].name "rack0"
+group[5].nodes[4]
+group[5].nodes[0].index 4
+group[5].nodes[1].index 5
+group[5].nodes[2].index 6
+group[5].nodes[3].index 17
+group[6].partitions ""
+group[6].index "1.1"
+group[6].name "rack1"
+group[6].nodes[4]
+group[6].nodes[0].index 10
+group[6].nodes[1].index 12
+group[6].nodes[2].index 13
+group[6].nodes[3].index 7 \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/java_retired.distribution b/vdslib/src/tests/distribution/testdata/java_retired.distribution
new file mode 100644
index 00000000000..1087c796fd7
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/java_retired.distribution
@@ -0,0 +1,8955 @@
+0 0 1 6
+0 0 2 6
+0 0 3 6
+0 0 4 6
+0 0 5 6
+1 0 1 6
+1 0 2 6
+1 0 3 6
+1 0 4 6
+1 0 5 6
+1 1 1 8
+1 1 2 8
+1 1 3 8
+1 1 4 8
+1 1 5 8
+2 0 1 6
+2 0 2 6
+2 0 3 6
+2 0 4 6
+2 0 5 6
+2 1 1 8
+2 1 2 8
+2 1 3 8
+2 1 4 8
+2 1 5 8
+2 2 1 2
+2 2 2 2
+2 2 3 2
+2 2 4 2
+2 2 5 2
+2 3 1 5
+2 3 2 5
+2 3 3 5
+2 3 4 5
+2 3 5 5
+3 0 1 6
+3 0 2 6
+3 0 3 6
+3 0 4 6
+3 0 5 6
+3 1 1 8
+3 1 2 8
+3 1 3 8
+3 1 4 8
+3 1 5 8
+3 2 1 2
+3 2 2 2
+3 2 3 2
+3 2 4 2
+3 2 5 2
+3 3 1 5
+3 3 2 5
+3 3 3 5
+3 3 4 5
+3 3 5 5
+3 4 1 12
+3 4 2 12
+3 4 3 12
+3 4 4 12
+3 4 5 12
+3 5 1 6
+3 5 2 6
+3 5 3 6
+3 5 4 6
+3 5 5 6
+3 6 1 8
+3 6 2 8
+3 6 3 8
+3 6 4 8
+3 6 5 8
+3 7 1 2
+3 7 2 2
+3 7 3 2
+3 7 4 2
+3 7 5 2
+4 0 1 6
+4 0 2 6
+4 0 3 6
+4 0 4 6
+4 0 5 6
+4 1 1 8
+4 1 2 8
+4 1 3 8
+4 1 4 8
+4 1 5 8
+4 2 1 2
+4 2 2 2
+4 2 3 2
+4 2 4 2
+4 2 5 2
+4 3 1 5
+4 3 2 5
+4 3 3 5
+4 3 4 5
+4 3 5 5
+4 4 1 12
+4 4 2 12
+4 4 3 12
+4 4 4 12
+4 4 5 12
+4 5 1 6
+4 5 2 6
+4 5 3 6
+4 5 4 6
+4 5 5 6
+4 6 1 8
+4 6 2 8
+4 6 3 8
+4 6 4 8
+4 6 5 8
+4 7 1 2
+4 7 2 2
+4 7 3 2
+4 7 4 2
+4 7 5 2
+4 8 1 8
+4 8 2 8
+4 8 3 8
+4 8 4 8
+4 8 5 8
+4 9 1 5
+4 9 2 5
+4 9 3 5
+4 9 4 5
+4 9 5 5
+4 10 1 13
+4 10 2 13
+4 10 3 13
+4 10 4 13
+4 10 5 13
+4 11 1 6
+4 11 2 6
+4 11 3 6
+4 11 4 6
+4 11 5 6
+4 12 1 6
+4 12 2 6
+4 12 3 6
+4 12 4 6
+4 12 5 6
+4 13 1 8
+4 13 2 8
+4 13 3 8
+4 13 4 8
+4 13 5 8
+4 14 1 0
+4 14 2 0
+4 14 3 0
+4 14 4 0
+4 14 5 0
+4 15 1 5
+4 15 2 5
+4 15 3 5
+4 15 4 5
+4 15 5 5
+5 0 1 6
+5 0 2 6
+5 0 3 6
+5 0 4 6
+5 0 5 6
+5 1 1 8
+5 1 2 8
+5 1 3 8
+5 1 4 8
+5 1 5 8
+5 2 1 2
+5 2 2 2
+5 2 3 2
+5 2 4 2
+5 2 5 2
+5 3 1 5
+5 3 2 5
+5 3 3 5
+5 3 4 5
+5 3 5 5
+5 4 1 12
+5 4 2 12
+5 4 3 12
+5 4 4 12
+5 4 5 12
+5 5 1 6
+5 5 2 6
+5 5 3 6
+5 5 4 6
+5 5 5 6
+5 6 1 8
+5 6 2 8
+5 6 3 8
+5 6 4 8
+5 6 5 8
+5 7 1 2
+5 7 2 2
+5 7 3 2
+5 7 4 2
+5 7 5 2
+5 8 1 8
+5 8 2 8
+5 8 3 8
+5 8 4 8
+5 8 5 8
+5 9 1 5
+5 9 2 5
+5 9 3 5
+5 9 4 5
+5 9 5 5
+5 10 1 13
+5 10 2 13
+5 10 3 13
+5 10 4 13
+5 10 5 13
+5 11 1 6
+5 11 2 6
+5 11 3 6
+5 11 4 6
+5 11 5 6
+5 12 1 6
+5 12 2 6
+5 12 3 6
+5 12 4 6
+5 12 5 6
+5 13 1 8
+5 13 2 8
+5 13 3 8
+5 13 4 8
+5 13 5 8
+5 14 1 0
+5 14 2 0
+5 14 3 0
+5 14 4 0
+5 14 5 0
+5 15 1 5
+5 15 2 5
+5 15 3 5
+5 15 4 5
+5 15 5 5
+5 16 1 7
+5 16 2 7
+5 16 3 7
+5 16 4 7
+5 16 5 7
+5 17 1 7
+5 17 2 7
+5 17 3 7
+5 17 4 7
+5 17 5 7
+5 18 1 17
+5 18 2 17
+5 18 3 17
+5 18 4 17
+5 18 5 17
+5 19 1 1
+5 19 2 1
+5 19 3 1
+5 19 4 1
+5 19 5 1
+5 20 1 8
+5 20 2 8
+5 20 3 8
+5 20 4 8
+5 20 5 8
+5 21 1 4
+5 21 2 4
+5 21 3 4
+5 21 4 4
+5 21 5 4
+5 22 1 4
+5 22 2 4
+5 22 3 4
+5 22 4 4
+5 22 5 4
+5 23 1 5
+5 23 2 5
+5 23 3 5
+5 23 4 5
+5 23 5 5
+5 24 1 0
+5 24 2 0
+5 24 3 0
+5 24 4 0
+5 24 5 0
+5 25 1 17
+5 25 2 17
+5 25 3 17
+5 25 4 17
+5 25 5 17
+5 26 1 8
+5 26 2 8
+5 26 3 8
+5 26 4 8
+5 26 5 8
+5 27 1 12
+5 27 2 12
+5 27 3 12
+5 27 4 12
+5 27 5 12
+5 28 1 7
+5 28 2 7
+5 28 3 7
+5 28 4 7
+5 28 5 7
+5 29 1 1
+5 29 2 1
+5 29 3 1
+5 29 4 1
+5 29 5 1
+5 30 1 10
+5 30 2 10
+5 30 3 10
+5 30 4 10
+5 30 5 10
+5 31 1 8
+5 31 2 8
+5 31 3 8
+5 31 4 8
+5 31 5 8
+6 0 1 6
+6 0 2 6
+6 0 3 6
+6 0 4 6
+6 0 5 6
+6 1 1 8
+6 1 2 8
+6 1 3 8
+6 1 4 8
+6 1 5 8
+6 2 1 2
+6 2 2 2
+6 2 3 2
+6 2 4 2
+6 2 5 2
+6 3 1 5
+6 3 2 5
+6 3 3 5
+6 3 4 5
+6 3 5 5
+6 4 1 12
+6 4 2 12
+6 4 3 12
+6 4 4 12
+6 4 5 12
+6 5 1 6
+6 5 2 6
+6 5 3 6
+6 5 4 6
+6 5 5 6
+6 6 1 8
+6 6 2 8
+6 6 3 8
+6 6 4 8
+6 6 5 8
+6 7 1 2
+6 7 2 2
+6 7 3 2
+6 7 4 2
+6 7 5 2
+6 8 1 8
+6 8 2 8
+6 8 3 8
+6 8 4 8
+6 8 5 8
+6 9 1 5
+6 9 2 5
+6 9 3 5
+6 9 4 5
+6 9 5 5
+6 10 1 13
+6 10 2 13
+6 10 3 13
+6 10 4 13
+6 10 5 13
+6 11 1 6
+6 11 2 6
+6 11 3 6
+6 11 4 6
+6 11 5 6
+6 12 1 6
+6 12 2 6
+6 12 3 6
+6 12 4 6
+6 12 5 6
+6 13 1 8
+6 13 2 8
+6 13 3 8
+6 13 4 8
+6 13 5 8
+6 14 1 0
+6 14 2 0
+6 14 3 0
+6 14 4 0
+6 14 5 0
+6 15 1 5
+6 15 2 5
+6 15 3 5
+6 15 4 5
+6 15 5 5
+6 16 1 7
+6 16 2 7
+6 16 3 7
+6 16 4 7
+6 16 5 7
+6 17 1 7
+6 17 2 7
+6 17 3 7
+6 17 4 7
+6 17 5 7
+6 18 1 17
+6 18 2 17
+6 18 3 17
+6 18 4 17
+6 18 5 17
+6 19 1 1
+6 19 2 1
+6 19 3 1
+6 19 4 1
+6 19 5 1
+6 20 1 8
+6 20 2 8
+6 20 3 8
+6 20 4 8
+6 20 5 8
+6 21 1 4
+6 21 2 4
+6 21 3 4
+6 21 4 4
+6 21 5 4
+6 22 1 4
+6 22 2 4
+6 22 3 4
+6 22 4 4
+6 22 5 4
+6 23 1 5
+6 23 2 5
+6 23 3 5
+6 23 4 5
+6 23 5 5
+6 24 1 0
+6 24 2 0
+6 24 3 0
+6 24 4 0
+6 24 5 0
+6 25 1 17
+6 25 2 17
+6 25 3 17
+6 25 4 17
+6 25 5 17
+6 26 1 8
+6 26 2 8
+6 26 3 8
+6 26 4 8
+6 26 5 8
+6 27 1 12
+6 27 2 12
+6 27 3 12
+6 27 4 12
+6 27 5 12
+6 28 1 7
+6 28 2 7
+6 28 3 7
+6 28 4 7
+6 28 5 7
+6 29 1 1
+6 29 2 1
+6 29 3 1
+6 29 4 1
+6 29 5 1
+6 30 1 10
+6 30 2 10
+6 30 3 10
+6 30 4 10
+6 30 5 10
+6 31 1 8
+6 31 2 8
+6 31 3 8
+6 31 4 8
+6 31 5 8
+6 32 1 5
+6 32 2 5
+6 32 3 5
+6 32 4 5
+6 32 5 5
+6 33 1 12
+6 33 2 12
+6 33 3 12
+6 33 4 12
+6 33 5 12
+6 34 1 1
+6 34 2 1
+6 34 3 1
+6 34 4 1
+6 34 5 1
+6 35 1 7
+6 35 2 7
+6 35 3 7
+6 35 4 7
+6 35 5 7
+6 36 1 3
+6 36 2 3
+6 36 3 3
+6 36 4 3
+6 36 5 3
+6 37 1 5
+6 37 2 5
+6 37 3 5
+6 37 4 5
+6 37 5 5
+6 38 1 3
+6 38 2 3
+6 38 3 3
+6 38 4 3
+6 38 5 3
+6 39 1 4
+6 39 2 4
+6 39 3 4
+6 39 4 4
+6 39 5 4
+6 40 1 5
+6 40 2 5
+6 40 3 5
+6 40 4 5
+6 40 5 5
+6 41 1 3
+6 41 2 3
+6 41 3 3
+6 41 4 3
+6 41 5 3
+6 42 1 4
+6 42 2 4
+6 42 3 4
+6 42 4 4
+6 42 5 4
+6 43 1 1
+6 43 2 1
+6 43 3 1
+6 43 4 1
+6 43 5 1
+6 44 1 8
+6 44 2 8
+6 44 3 8
+6 44 4 8
+6 44 5 8
+6 45 1 10
+6 45 2 10
+6 45 3 10
+6 45 4 10
+6 45 5 10
+6 46 1 5
+6 46 2 5
+6 46 3 5
+6 46 4 5
+6 46 5 5
+6 47 1 7
+6 47 2 7
+6 47 3 7
+6 47 4 7
+6 47 5 7
+6 48 1 0
+6 48 2 0
+6 48 3 0
+6 48 4 0
+6 48 5 0
+6 49 1 8
+6 49 2 8
+6 49 3 8
+6 49 4 8
+6 49 5 8
+6 50 1 9
+6 50 2 9
+6 50 3 9
+6 50 4 9
+6 50 5 9
+6 51 1 7
+6 51 2 7
+6 51 3 7
+6 51 4 7
+6 51 5 7
+6 52 1 13
+6 52 2 13
+6 52 3 13
+6 52 4 13
+6 52 5 13
+6 53 1 10
+6 53 2 10
+6 53 3 10
+6 53 4 10
+6 53 5 10
+6 54 1 1
+6 54 2 1
+6 54 3 1
+6 54 4 1
+6 54 5 1
+6 55 1 8
+6 55 2 8
+6 55 3 8
+6 55 4 8
+6 55 5 8
+6 56 1 8
+6 56 2 8
+6 56 3 8
+6 56 4 8
+6 56 5 8
+6 57 1 6
+6 57 2 6
+6 57 3 6
+6 57 4 6
+6 57 5 6
+6 58 1 6
+6 58 2 6
+6 58 3 6
+6 58 4 6
+6 58 5 6
+6 59 1 1
+6 59 2 1
+6 59 3 1
+6 59 4 1
+6 59 5 1
+6 60 1 6
+6 60 2 6
+6 60 3 6
+6 60 4 6
+6 60 5 6
+6 61 1 3
+6 61 2 3
+6 61 3 3
+6 61 4 3
+6 61 5 3
+6 62 1 10
+6 62 2 10
+6 62 3 10
+6 62 4 10
+6 62 5 10
+6 63 1 13
+6 63 2 13
+6 63 3 13
+6 63 4 13
+6 63 5 13
+7 57 1 6
+7 57 2 6
+7 57 3 6
+7 57 4 6
+7 57 5 6
+7 93 1 12
+7 93 2 12
+7 93 3 12
+7 93 4 12
+7 93 5 12
+7 18 1 17
+7 18 2 17
+7 18 3 17
+7 18 4 17
+7 18 5 17
+7 93 1 12
+7 93 2 12
+7 93 3 12
+7 93 4 12
+7 93 5 12
+7 33 1 12
+7 33 2 12
+7 33 3 12
+7 33 4 12
+7 33 5 12
+7 95 1 2
+7 95 2 2
+7 95 3 2
+7 95 4 2
+7 95 5 2
+7 124 1 0
+7 124 2 0
+7 124 3 0
+7 124 4 0
+7 124 5 0
+7 101 1 3
+7 101 2 3
+7 101 3 3
+7 101 4 3
+7 101 5 3
+7 78 1 7
+7 78 2 7
+7 78 3 7
+7 78 4 7
+7 78 5 7
+7 105 1 14
+7 105 2 14
+7 105 3 14
+7 105 4 14
+7 105 5 14
+7 55 1 8
+7 55 2 8
+7 55 3 8
+7 55 4 8
+7 55 5 8
+7 105 1 14
+7 105 2 14
+7 105 3 14
+7 105 4 14
+7 105 5 14
+7 113 1 8
+7 113 2 8
+7 113 3 8
+7 113 4 8
+7 113 5 8
+7 38 1 3
+7 38 2 3
+7 38 3 3
+7 38 4 3
+7 38 5 3
+7 51 1 7
+7 51 2 7
+7 51 3 7
+7 51 4 7
+7 51 5 7
+7 39 1 4
+7 39 2 4
+7 39 3 4
+7 39 4 4
+7 39 5 4
+7 89 1 14
+7 89 2 14
+7 89 3 14
+7 89 4 14
+7 89 5 14
+7 4 1 12
+7 4 2 12
+7 4 3 12
+7 4 4 12
+7 4 5 12
+7 68 1 6
+7 68 2 6
+7 68 3 6
+7 68 4 6
+7 68 5 6
+7 96 1 4
+7 96 2 4
+7 96 3 4
+7 96 4 4
+7 96 5 4
+7 126 1 10
+7 126 2 10
+7 126 3 10
+7 126 4 10
+7 126 5 10
+7 54 1 1
+7 54 2 1
+7 54 3 1
+7 54 4 1
+7 54 5 1
+7 34 1 1
+7 34 2 1
+7 34 3 1
+7 34 4 1
+7 34 5 1
+7 89 1 14
+7 89 2 14
+7 89 3 14
+7 89 4 14
+7 89 5 14
+7 122 1 2
+7 122 2 2
+7 122 3 2
+7 122 4 2
+7 122 5 2
+7 53 1 10
+7 53 2 10
+7 53 3 10
+7 53 4 10
+7 53 5 10
+7 105 1 14
+7 105 2 14
+7 105 3 14
+7 105 4 14
+7 105 5 14
+7 90 1 2
+7 90 2 2
+7 90 3 2
+7 90 4 2
+7 90 5 2
+7 11 1 6
+7 11 2 6
+7 11 3 6
+7 11 4 6
+7 11 5 6
+7 59 1 1
+7 59 2 1
+7 59 3 1
+7 59 4 1
+7 59 5 1
+7 26 1 8
+7 26 2 8
+7 26 3 8
+7 26 4 8
+7 26 5 8
+7 50 1 9
+7 50 2 9
+7 50 3 9
+7 50 4 9
+7 50 5 9
+7 19 1 1
+7 19 2 1
+7 19 3 1
+7 19 4 1
+7 19 5 1
+7 70 1 0
+7 70 2 0
+7 70 3 0
+7 70 4 0
+7 70 5 0
+7 25 1 17
+7 25 2 17
+7 25 3 17
+7 25 4 17
+7 25 5 17
+7 48 1 0
+7 48 2 0
+7 48 3 0
+7 48 4 0
+7 48 5 0
+7 24 1 0
+7 24 2 0
+7 24 3 0
+7 24 4 0
+7 24 5 0
+7 27 1 12
+7 27 2 12
+7 27 3 12
+7 27 4 12
+7 27 5 12
+7 44 1 8
+7 44 2 8
+7 44 3 8
+7 44 4 8
+7 44 5 8
+7 44 1 8
+7 44 2 8
+7 44 3 8
+7 44 4 8
+7 44 5 8
+7 68 1 6
+7 68 2 6
+7 68 3 6
+7 68 4 6
+7 68 5 6
+7 65 1 1
+7 65 2 1
+7 65 3 1
+7 65 4 1
+7 65 5 1
+7 2 1 2
+7 2 2 2
+7 2 3 2
+7 2 4 2
+7 2 5 2
+7 124 1 0
+7 124 2 0
+7 124 3 0
+7 124 4 0
+7 124 5 0
+7 101 1 3
+7 101 2 3
+7 101 3 3
+7 101 4 3
+7 101 5 3
+7 2 1 2
+7 2 2 2
+7 2 3 2
+7 2 4 2
+7 2 5 2
+7 42 1 4
+7 42 2 4
+7 42 3 4
+7 42 4 4
+7 42 5 4
+7 127 1 2
+7 127 2 2
+7 127 3 2
+7 127 4 2
+7 127 5 2
+7 110 1 3
+7 110 2 3
+7 110 3 3
+7 110 4 3
+7 110 5 3
+7 109 1 17
+7 109 2 17
+7 109 3 17
+7 109 4 17
+7 109 5 17
+7 24 1 0
+7 24 2 0
+7 24 3 0
+7 24 4 0
+7 24 5 0
+7 22 1 4
+7 22 2 4
+7 22 3 4
+7 22 4 4
+7 22 5 4
+7 117 1 0
+7 117 2 0
+7 117 3 0
+7 117 4 0
+7 117 5 0
+7 87 1 0
+7 87 2 0
+7 87 3 0
+7 87 4 0
+7 87 5 0
+7 35 1 7
+7 35 2 7
+7 35 3 7
+7 35 4 7
+7 35 5 7
+7 37 1 5
+7 37 2 5
+7 37 3 5
+7 37 4 5
+7 37 5 5
+7 51 1 7
+7 51 2 7
+7 51 3 7
+7 51 4 7
+7 51 5 7
+7 85 1 9
+7 85 2 9
+7 85 3 9
+7 85 4 9
+7 85 5 9
+7 10 1 13
+7 10 2 13
+7 10 3 13
+7 10 4 13
+7 10 5 13
+7 23 1 5
+7 23 2 5
+7 23 3 5
+7 23 4 5
+7 23 5 5
+7 7 1 2
+7 7 2 2
+7 7 3 2
+7 7 4 2
+7 7 5 2
+7 67 1 5
+7 67 2 5
+7 67 3 5
+7 67 4 5
+7 67 5 5
+7 106 1 1
+7 106 2 1
+7 106 3 1
+7 106 4 1
+7 106 5 1
+7 88 1 5
+7 88 2 5
+7 88 3 5
+7 88 4 5
+7 88 5 5
+8 91 1 13
+8 91 2 13
+8 91 3 13
+8 91 4 13
+8 91 5 13
+8 237 1 6
+8 237 2 6
+8 237 3 6
+8 237 4 6
+8 237 5 6
+8 214 1 17
+8 214 2 17
+8 214 3 17
+8 214 4 17
+8 214 5 17
+8 65 1 1
+8 65 2 1
+8 65 3 1
+8 65 4 1
+8 65 5 1
+8 132 1 13
+8 132 2 13
+8 132 3 13
+8 132 4 13
+8 132 5 13
+8 211 1 3
+8 211 2 3
+8 211 3 3
+8 211 4 3
+8 211 5 3
+8 184 1 17
+8 184 2 17
+8 184 3 17
+8 184 4 17
+8 184 5 17
+8 171 1 6
+8 171 2 6
+8 171 3 6
+8 171 4 6
+8 171 5 6
+8 63 1 13
+8 63 2 13
+8 63 3 13
+8 63 4 13
+8 63 5 13
+8 179 1 10
+8 179 2 10
+8 179 3 10
+8 179 4 10
+8 179 5 10
+8 249 1 5
+8 249 2 5
+8 249 3 5
+8 249 4 5
+8 249 5 5
+8 102 1 6
+8 102 2 6
+8 102 3 6
+8 102 4 6
+8 102 5 6
+8 170 1 14
+8 170 2 14
+8 170 3 14
+8 170 4 14
+8 170 5 14
+8 199 1 6
+8 199 2 6
+8 199 3 6
+8 199 4 6
+8 199 5 6
+8 18 1 17
+8 18 2 17
+8 18 3 17
+8 18 4 17
+8 18 5 17
+8 147 1 4
+8 147 2 4
+8 147 3 4
+8 147 4 4
+8 147 5 4
+8 58 1 6
+8 58 2 6
+8 58 3 6
+8 58 4 6
+8 58 5 6
+8 185 1 14
+8 185 2 14
+8 185 3 14
+8 185 4 14
+8 185 5 14
+8 16 1 7
+8 16 2 7
+8 16 3 7
+8 16 4 7
+8 16 5 7
+8 9 1 5
+8 9 2 5
+8 9 3 5
+8 9 4 5
+8 9 5 5
+8 54 1 1
+8 54 2 1
+8 54 3 1
+8 54 4 1
+8 54 5 1
+8 44 1 8
+8 44 2 8
+8 44 3 8
+8 44 4 8
+8 44 5 8
+8 22 1 4
+8 22 2 4
+8 22 3 4
+8 22 4 4
+8 22 5 4
+8 212 1 17
+8 212 2 17
+8 212 3 17
+8 212 4 17
+8 212 5 17
+8 57 1 6
+8 57 2 6
+8 57 3 6
+8 57 4 6
+8 57 5 6
+8 51 1 7
+8 51 2 7
+8 51 3 7
+8 51 4 7
+8 51 5 7
+8 217 1 12
+8 217 2 12
+8 217 3 12
+8 217 4 12
+8 217 5 12
+8 176 1 2
+8 176 2 2
+8 176 3 2
+8 176 4 2
+8 176 5 2
+8 180 1 14
+8 180 2 14
+8 180 3 14
+8 180 4 14
+8 180 5 14
+8 216 1 4
+8 216 2 4
+8 216 3 4
+8 216 4 4
+8 216 5 4
+8 34 1 1
+8 34 2 1
+8 34 3 1
+8 34 4 1
+8 34 5 1
+8 146 1 5
+8 146 2 5
+8 146 3 5
+8 146 4 5
+8 146 5 5
+8 105 1 14
+8 105 2 14
+8 105 3 14
+8 105 4 14
+8 105 5 14
+8 151 1 12
+8 151 2 12
+8 151 3 12
+8 151 4 12
+8 151 5 12
+8 80 1 0
+8 80 2 0
+8 80 3 0
+8 80 4 0
+8 80 5 0
+8 32 1 5
+8 32 2 5
+8 32 3 5
+8 32 4 5
+8 32 5 5
+8 241 1 1
+8 241 2 1
+8 241 3 1
+8 241 4 1
+8 241 5 1
+8 224 1 7
+8 224 2 7
+8 224 3 7
+8 224 4 7
+8 224 5 7
+8 211 1 3
+8 211 2 3
+8 211 3 3
+8 211 4 3
+8 211 5 3
+8 52 1 13
+8 52 2 13
+8 52 3 13
+8 52 4 13
+8 52 5 13
+8 56 1 8
+8 56 2 8
+8 56 3 8
+8 56 4 8
+8 56 5 8
+8 152 1 9
+8 152 2 9
+8 152 3 9
+8 152 4 9
+8 152 5 9
+8 178 1 0
+8 178 2 0
+8 178 3 0
+8 178 4 0
+8 178 5 0
+8 93 1 12
+8 93 2 12
+8 93 3 12
+8 93 4 12
+8 93 5 12
+8 251 1 2
+8 251 2 2
+8 251 3 2
+8 251 4 2
+8 251 5 2
+8 152 1 9
+8 152 2 9
+8 152 3 9
+8 152 4 9
+8 152 5 9
+8 6 1 8
+8 6 2 8
+8 6 3 8
+8 6 4 8
+8 6 5 8
+8 93 1 12
+8 93 2 12
+8 93 3 12
+8 93 4 12
+8 93 5 12
+8 81 1 10
+8 81 2 10
+8 81 3 10
+8 81 4 10
+8 81 5 10
+8 45 1 10
+8 45 2 10
+8 45 3 10
+8 45 4 10
+8 45 5 10
+8 125 1 14
+8 125 2 14
+8 125 3 14
+8 125 4 14
+8 125 5 14
+8 172 1 4
+8 172 2 4
+8 172 3 4
+8 172 4 4
+8 172 5 4
+8 31 1 8
+8 31 2 8
+8 31 3 8
+8 31 4 8
+8 31 5 8
+8 150 1 9
+8 150 2 9
+8 150 3 9
+8 150 4 9
+8 150 5 9
+8 216 1 4
+8 216 2 4
+8 216 3 4
+8 216 4 4
+8 216 5 4
+8 243 1 15
+8 243 2 15
+8 243 3 15
+8 243 4 15
+8 243 5 15
+8 162 1 14
+8 162 2 14
+8 162 3 14
+8 162 4 14
+8 162 5 14
+8 138 1 14
+8 138 2 14
+8 138 3 14
+8 138 4 14
+8 138 5 14
+8 109 1 17
+8 109 2 17
+8 109 3 17
+8 109 4 17
+8 109 5 17
+8 146 1 5
+8 146 2 5
+8 146 3 5
+8 146 4 5
+8 146 5 5
+8 234 1 4
+8 234 2 4
+8 234 3 4
+8 234 4 4
+8 234 5 4
+8 175 1 15
+8 175 2 15
+8 175 3 15
+8 175 4 15
+8 175 5 15
+8 165 1 5
+8 165 2 5
+8 165 3 5
+8 165 4 5
+8 165 5 5
+8 28 1 7
+8 28 2 7
+8 28 3 7
+8 28 4 7
+8 28 5 7
+9 47 1 7
+9 47 2 7
+9 47 3 7
+9 47 4 7
+9 47 5 7
+9 163 1 14
+9 163 2 14
+9 163 3 14
+9 163 4 14
+9 163 5 14
+9 176 1 2
+9 176 2 2
+9 176 3 2
+9 176 4 2
+9 176 5 2
+9 59 1 1
+9 59 2 1
+9 59 3 1
+9 59 4 1
+9 59 5 1
+9 76 1 1
+9 76 2 1
+9 76 3 1
+9 76 4 1
+9 76 5 1
+9 260 1 7
+9 260 2 7
+9 260 3 7
+9 260 4 7
+9 260 5 7
+9 324 1 3
+9 324 2 3
+9 324 3 3
+9 324 4 3
+9 324 5 3
+9 160 1 13
+9 160 2 13
+9 160 3 13
+9 160 4 13
+9 160 5 13
+9 137 1 5
+9 137 2 5
+9 137 3 5
+9 137 4 5
+9 137 5 5
+9 476 1 7
+9 476 2 7
+9 476 3 7
+9 476 4 7
+9 476 5 7
+9 57 1 6
+9 57 2 6
+9 57 3 6
+9 57 4 6
+9 57 5 6
+9 204 1 1
+9 204 2 1
+9 204 3 1
+9 204 4 1
+9 204 5 1
+9 105 1 14
+9 105 2 14
+9 105 3 14
+9 105 4 14
+9 105 5 14
+9 307 1 5
+9 307 2 5
+9 307 3 5
+9 307 4 5
+9 307 5 5
+9 37 1 5
+9 37 2 5
+9 37 3 5
+9 37 4 5
+9 37 5 5
+9 297 1 9
+9 297 2 9
+9 297 3 9
+9 297 4 9
+9 297 5 9
+9 180 1 14
+9 180 2 14
+9 180 3 14
+9 180 4 14
+9 180 5 14
+9 503 1 15
+9 503 2 15
+9 503 3 15
+9 503 4 15
+9 503 5 15
+9 287 1 17
+9 287 2 17
+9 287 3 17
+9 287 4 17
+9 287 5 17
+9 325 1 1
+9 325 2 1
+9 325 3 1
+9 325 4 1
+9 325 5 1
+9 500 1 5
+9 500 2 5
+9 500 3 5
+9 500 4 5
+9 500 5 5
+9 119 1 14
+9 119 2 14
+9 119 3 14
+9 119 4 14
+9 119 5 14
+9 327 1 8
+9 327 2 8
+9 327 3 8
+9 327 4 8
+9 327 5 8
+9 83 1 3
+9 83 2 3
+9 83 3 3
+9 83 4 3
+9 83 5 3
+9 249 1 5
+9 249 2 5
+9 249 3 5
+9 249 4 5
+9 249 5 5
+9 230 1 17
+9 230 2 17
+9 230 3 17
+9 230 4 17
+9 230 5 17
+9 316 1 4
+9 316 2 4
+9 316 3 4
+9 316 4 4
+9 316 5 4
+9 424 1 0
+9 424 2 0
+9 424 3 0
+9 424 4 0
+9 424 5 0
+9 341 1 8
+9 341 2 8
+9 341 3 8
+9 341 4 8
+9 341 5 8
+9 478 1 9
+9 478 2 9
+9 478 3 9
+9 478 4 9
+9 478 5 9
+9 164 1 0
+9 164 2 0
+9 164 3 0
+9 164 4 0
+9 164 5 0
+9 319 1 12
+9 319 2 12
+9 319 3 12
+9 319 4 12
+9 319 5 12
+9 481 1 1
+9 481 2 1
+9 481 3 1
+9 481 4 1
+9 481 5 1
+9 218 1 0
+9 218 2 0
+9 218 3 0
+9 218 4 0
+9 218 5 0
+9 168 1 2
+9 168 2 2
+9 168 3 2
+9 168 4 2
+9 168 5 2
+9 54 1 1
+9 54 2 1
+9 54 3 1
+9 54 4 1
+9 54 5 1
+9 310 1 5
+9 310 2 5
+9 310 3 5
+9 310 4 5
+9 310 5 5
+9 186 1 17
+9 186 2 17
+9 186 3 17
+9 186 4 17
+9 186 5 17
+9 116 1 5
+9 116 2 5
+9 116 3 5
+9 116 4 5
+9 116 5 5
+9 335 1 7
+9 335 2 7
+9 335 3 7
+9 335 4 7
+9 335 5 7
+9 53 1 10
+9 53 2 10
+9 53 3 10
+9 53 4 10
+9 53 5 10
+9 67 1 5
+9 67 2 5
+9 67 3 5
+9 67 4 5
+9 67 5 5
+9 444 1 6
+9 444 2 6
+9 444 3 6
+9 444 4 6
+9 444 5 6
+9 368 1 12
+9 368 2 12
+9 368 3 12
+9 368 4 12
+9 368 5 12
+9 128 1 14
+9 128 2 14
+9 128 3 14
+9 128 4 14
+9 128 5 14
+9 157 1 8
+9 157 2 8
+9 157 3 8
+9 157 4 8
+9 157 5 8
+9 306 1 1
+9 306 2 1
+9 306 3 1
+9 306 4 1
+9 306 5 1
+9 35 1 7
+9 35 2 7
+9 35 3 7
+9 35 4 7
+9 35 5 7
+9 254 1 13
+9 254 2 13
+9 254 3 13
+9 254 4 13
+9 254 5 13
+9 467 1 2
+9 467 2 2
+9 467 3 2
+9 467 4 2
+9 467 5 2
+9 273 1 15
+9 273 2 15
+9 273 3 15
+9 273 4 15
+9 273 5 15
+9 23 1 5
+9 23 2 5
+9 23 3 5
+9 23 4 5
+9 23 5 5
+9 91 1 13
+9 91 2 13
+9 91 3 13
+9 91 4 13
+9 91 5 13
+9 342 1 2
+9 342 2 2
+9 342 3 2
+9 342 4 2
+9 342 5 2
+9 405 1 9
+9 405 2 9
+9 405 3 9
+9 405 4 9
+9 405 5 9
+9 413 1 4
+9 413 2 4
+9 413 3 4
+9 413 4 4
+9 413 5 4
+9 389 1 17
+9 389 2 17
+9 389 3 17
+9 389 4 17
+9 389 5 17
+9 123 1 7
+9 123 2 7
+9 123 3 7
+9 123 4 7
+9 123 5 7
+9 384 1 4
+9 384 2 4
+9 384 3 4
+9 384 4 4
+9 384 5 4
+9 299 1 5
+9 299 2 5
+9 299 3 5
+9 299 4 5
+9 299 5 5
+9 48 1 0
+9 48 2 0
+9 48 3 0
+9 48 4 0
+9 48 5 0
+9 248 1 15
+9 248 2 15
+9 248 3 15
+9 248 4 15
+9 248 5 15
+9 151 1 12
+9 151 2 12
+9 151 3 12
+9 151 4 12
+9 151 5 12
+9 477 1 12
+9 477 2 12
+9 477 3 12
+9 477 4 12
+9 477 5 12
+10 436 1 5
+10 436 2 5
+10 436 3 5
+10 436 4 5
+10 436 5 5
+10 128 1 14
+10 128 2 14
+10 128 3 14
+10 128 4 14
+10 128 5 14
+10 545 1 7
+10 545 2 7
+10 545 3 7
+10 545 4 7
+10 545 5 7
+10 332 1 1
+10 332 2 1
+10 332 3 1
+10 332 4 1
+10 332 5 1
+10 758 1 8
+10 758 2 8
+10 758 3 8
+10 758 4 8
+10 758 5 8
+10 625 1 14
+10 625 2 14
+10 625 3 14
+10 625 4 14
+10 625 5 14
+10 160 1 13
+10 160 2 13
+10 160 3 13
+10 160 4 13
+10 160 5 13
+10 194 1 6
+10 194 2 6
+10 194 3 6
+10 194 4 6
+10 194 5 6
+10 172 1 4
+10 172 2 4
+10 172 3 4
+10 172 4 4
+10 172 5 4
+10 866 1 5
+10 866 2 5
+10 866 3 5
+10 866 4 5
+10 866 5 5
+10 120 1 15
+10 120 2 15
+10 120 3 15
+10 120 4 15
+10 120 5 15
+10 923 1 3
+10 923 2 3
+10 923 3 3
+10 923 4 3
+10 923 5 3
+10 813 1 1
+10 813 2 1
+10 813 3 1
+10 813 4 1
+10 813 5 1
+10 493 1 1
+10 493 2 1
+10 493 3 1
+10 493 4 1
+10 493 5 1
+10 748 1 8
+10 748 2 8
+10 748 3 8
+10 748 4 8
+10 748 5 8
+10 104 1 1
+10 104 2 1
+10 104 3 1
+10 104 4 1
+10 104 5 1
+10 326 1 7
+10 326 2 7
+10 326 3 7
+10 326 4 7
+10 326 5 7
+10 573 1 7
+10 573 2 7
+10 573 3 7
+10 573 4 7
+10 573 5 7
+10 754 1 13
+10 754 2 13
+10 754 3 13
+10 754 4 13
+10 754 5 13
+10 146 1 5
+10 146 2 5
+10 146 3 5
+10 146 4 5
+10 146 5 5
+10 697 1 14
+10 697 2 14
+10 697 3 14
+10 697 4 14
+10 697 5 14
+10 150 1 9
+10 150 2 9
+10 150 3 9
+10 150 4 9
+10 150 5 9
+10 948 1 7
+10 948 2 7
+10 948 3 7
+10 948 4 7
+10 948 5 7
+10 726 1 14
+10 726 2 14
+10 726 3 14
+10 726 4 14
+10 726 5 14
+10 698 1 3
+10 698 2 3
+10 698 3 3
+10 698 4 3
+10 698 5 3
+10 974 1 9
+10 974 2 9
+10 974 3 9
+10 974 4 9
+10 974 5 9
+10 787 1 5
+10 787 2 5
+10 787 3 5
+10 787 4 5
+10 787 5 5
+10 449 1 5
+10 449 2 5
+10 449 3 5
+10 449 4 5
+10 449 5 5
+10 624 1 15
+10 624 2 15
+10 624 3 15
+10 624 4 15
+10 624 5 15
+10 972 1 1
+10 972 2 1
+10 972 3 1
+10 972 4 1
+10 972 5 1
+10 31 1 8
+10 31 2 8
+10 31 3 8
+10 31 4 8
+10 31 5 8
+10 568 1 17
+10 568 2 17
+10 568 3 17
+10 568 4 17
+10 568 5 17
+10 890 1 6
+10 890 2 6
+10 890 3 6
+10 890 4 6
+10 890 5 6
+10 16 1 7
+10 16 2 7
+10 16 3 7
+10 16 4 7
+10 16 5 7
+10 416 1 7
+10 416 2 7
+10 416 3 7
+10 416 4 7
+10 416 5 7
+10 499 1 5
+10 499 2 5
+10 499 3 5
+10 499 4 5
+10 499 5 5
+10 615 1 0
+10 615 2 0
+10 615 3 0
+10 615 4 0
+10 615 5 0
+10 555 1 8
+10 555 2 8
+10 555 3 8
+10 555 4 8
+10 555 5 8
+10 144 1 6
+10 144 2 6
+10 144 3 6
+10 144 4 6
+10 144 5 6
+10 509 1 17
+10 509 2 17
+10 509 3 17
+10 509 4 17
+10 509 5 17
+10 316 1 4
+10 316 2 4
+10 316 3 4
+10 316 4 4
+10 316 5 4
+10 66 1 14
+10 66 2 14
+10 66 3 14
+10 66 4 14
+10 66 5 14
+10 671 1 10
+10 671 2 10
+10 671 3 10
+10 671 4 10
+10 671 5 10
+10 310 1 5
+10 310 2 5
+10 310 3 5
+10 310 4 5
+10 310 5 5
+10 499 1 5
+10 499 2 5
+10 499 3 5
+10 499 4 5
+10 499 5 5
+10 911 1 8
+10 911 2 8
+10 911 3 8
+10 911 4 8
+10 911 5 8
+10 174 1 6
+10 174 2 6
+10 174 3 6
+10 174 4 6
+10 174 5 6
+10 721 1 5
+10 721 2 5
+10 721 3 5
+10 721 4 5
+10 721 5 5
+10 246 1 17
+10 246 2 17
+10 246 3 17
+10 246 4 17
+10 246 5 17
+10 736 1 0
+10 736 2 0
+10 736 3 0
+10 736 4 0
+10 736 5 0
+10 340 1 5
+10 340 2 5
+10 340 3 5
+10 340 4 5
+10 340 5 5
+10 214 1 17
+10 214 2 17
+10 214 3 17
+10 214 4 17
+10 214 5 17
+10 936 1 17
+10 936 2 17
+10 936 3 17
+10 936 4 17
+10 936 5 17
+10 278 1 14
+10 278 2 14
+10 278 3 14
+10 278 4 14
+10 278 5 14
+10 860 1 9
+10 860 2 9
+10 860 3 9
+10 860 4 9
+10 860 5 9
+10 673 1 3
+10 673 2 3
+10 673 3 3
+10 673 4 3
+10 673 5 3
+10 732 1 14
+10 732 2 14
+10 732 3 14
+10 732 4 14
+10 732 5 14
+10 936 1 17
+10 936 2 17
+10 936 3 17
+10 936 4 17
+10 936 5 17
+10 69 1 1
+10 69 2 1
+10 69 3 1
+10 69 4 1
+10 69 5 1
+10 865 1 14
+10 865 2 14
+10 865 3 14
+10 865 4 14
+10 865 5 14
+10 348 1 14
+10 348 2 14
+10 348 3 14
+10 348 4 14
+10 348 5 14
+10 285 1 9
+10 285 2 9
+10 285 3 9
+10 285 4 9
+10 285 5 9
+10 705 1 6
+10 705 2 6
+10 705 3 6
+10 705 4 6
+10 705 5 6
+10 154 1 13
+10 154 2 13
+10 154 3 13
+10 154 4 13
+10 154 5 13
+11 1671 1 3
+11 1671 2 3
+11 1671 3 3
+11 1671 4 3
+11 1671 5 3
+11 1334 1 1
+11 1334 2 1
+11 1334 3 1
+11 1334 4 1
+11 1334 5 1
+11 763 1 7
+11 763 2 7
+11 763 3 7
+11 763 4 7
+11 763 5 7
+11 1607 1 1
+11 1607 2 1
+11 1607 3 1
+11 1607 4 1
+11 1607 5 1
+11 1725 1 0
+11 1725 2 0
+11 1725 3 0
+11 1725 4 0
+11 1725 5 0
+11 162 1 14
+11 162 2 14
+11 162 3 14
+11 162 4 14
+11 162 5 14
+11 1068 1 4
+11 1068 2 4
+11 1068 3 4
+11 1068 4 4
+11 1068 5 4
+11 1207 1 14
+11 1207 2 14
+11 1207 3 14
+11 1207 4 14
+11 1207 5 14
+11 501 1 6
+11 501 2 6
+11 501 3 6
+11 501 4 6
+11 501 5 6
+11 1419 1 7
+11 1419 2 7
+11 1419 3 7
+11 1419 4 7
+11 1419 5 7
+11 440 1 14
+11 440 2 14
+11 440 3 14
+11 440 4 14
+11 440 5 14
+11 512 1 6
+11 512 2 6
+11 512 3 6
+11 512 4 6
+11 512 5 6
+11 1260 1 4
+11 1260 2 4
+11 1260 3 4
+11 1260 4 4
+11 1260 5 4
+11 1626 1 0
+11 1626 2 0
+11 1626 3 0
+11 1626 4 0
+11 1626 5 0
+11 1023 1 2
+11 1023 2 2
+11 1023 3 2
+11 1023 4 2
+11 1023 5 2
+11 510 1 14
+11 510 2 14
+11 510 3 14
+11 510 4 14
+11 510 5 14
+11 960 1 15
+11 960 2 15
+11 960 3 15
+11 960 4 15
+11 960 5 15
+11 1403 1 4
+11 1403 2 4
+11 1403 3 4
+11 1403 4 4
+11 1403 5 4
+11 1281 1 0
+11 1281 2 0
+11 1281 3 0
+11 1281 4 0
+11 1281 5 0
+11 1230 1 8
+11 1230 2 8
+11 1230 3 8
+11 1230 4 8
+11 1230 5 8
+11 631 1 4
+11 631 2 4
+11 631 3 4
+11 631 4 4
+11 631 5 4
+11 481 1 1
+11 481 2 1
+11 481 3 1
+11 481 4 1
+11 481 5 1
+11 229 1 12
+11 229 2 12
+11 229 3 12
+11 229 4 12
+11 229 5 12
+11 853 1 15
+11 853 2 15
+11 853 3 15
+11 853 4 15
+11 853 5 15
+11 1401 1 17
+11 1401 2 17
+11 1401 3 17
+11 1401 4 17
+11 1401 5 17
+11 896 1 4
+11 896 2 4
+11 896 3 4
+11 896 4 4
+11 896 5 4
+11 1654 1 7
+11 1654 2 7
+11 1654 3 7
+11 1654 4 7
+11 1654 5 7
+11 953 1 5
+11 953 2 5
+11 953 3 5
+11 953 4 5
+11 953 5 5
+11 530 1 6
+11 530 2 6
+11 530 3 6
+11 530 4 6
+11 530 5 6
+11 2002 1 12
+11 2002 2 12
+11 2002 3 12
+11 2002 4 12
+11 2002 5 12
+11 1953 1 2
+11 1953 2 2
+11 1953 3 2
+11 1953 4 2
+11 1953 5 2
+11 1509 1 4
+11 1509 2 4
+11 1509 3 4
+11 1509 4 4
+11 1509 5 4
+11 1778 1 10
+11 1778 2 10
+11 1778 3 10
+11 1778 4 10
+11 1778 5 10
+11 1619 1 14
+11 1619 2 14
+11 1619 3 14
+11 1619 4 14
+11 1619 5 14
+11 504 1 2
+11 504 2 2
+11 504 3 2
+11 504 4 2
+11 504 5 2
+11 9 1 5
+11 9 2 5
+11 9 3 5
+11 9 4 5
+11 9 5 5
+11 1196 1 14
+11 1196 2 14
+11 1196 3 14
+11 1196 4 14
+11 1196 5 14
+11 1285 1 12
+11 1285 2 12
+11 1285 3 12
+11 1285 4 12
+11 1285 5 12
+11 1842 1 5
+11 1842 2 5
+11 1842 3 5
+11 1842 4 5
+11 1842 5 5
+11 792 1 12
+11 792 2 12
+11 792 3 12
+11 792 4 12
+11 792 5 12
+11 1594 1 12
+11 1594 2 12
+11 1594 3 12
+11 1594 4 12
+11 1594 5 12
+11 1261 1 5
+11 1261 2 5
+11 1261 3 5
+11 1261 4 5
+11 1261 5 5
+11 1448 1 0
+11 1448 2 0
+11 1448 3 0
+11 1448 4 0
+11 1448 5 0
+11 1865 1 9
+11 1865 2 9
+11 1865 3 9
+11 1865 4 9
+11 1865 5 9
+11 375 1 4
+11 375 2 4
+11 375 3 4
+11 375 4 4
+11 375 5 4
+11 1684 1 9
+11 1684 2 9
+11 1684 3 9
+11 1684 4 9
+11 1684 5 9
+11 218 1 0
+11 218 2 0
+11 218 3 0
+11 218 4 0
+11 218 5 0
+11 151 1 12
+11 151 2 12
+11 151 3 12
+11 151 4 12
+11 151 5 12
+11 1956 1 10
+11 1956 2 10
+11 1956 3 10
+11 1956 4 10
+11 1956 5 10
+11 1670 1 9
+11 1670 2 9
+11 1670 3 9
+11 1670 4 9
+11 1670 5 9
+11 488 1 1
+11 488 2 1
+11 488 3 1
+11 488 4 1
+11 488 5 1
+11 833 1 7
+11 833 2 7
+11 833 3 7
+11 833 4 7
+11 833 5 7
+11 1508 1 6
+11 1508 2 6
+11 1508 3 6
+11 1508 4 6
+11 1508 5 6
+11 470 1 12
+11 470 2 12
+11 470 3 12
+11 470 4 12
+11 470 5 12
+11 26 1 8
+11 26 2 8
+11 26 3 8
+11 26 4 8
+11 26 5 8
+11 74 1 12
+11 74 2 12
+11 74 3 12
+11 74 4 12
+11 74 5 12
+11 1471 1 10
+11 1471 2 10
+11 1471 3 10
+11 1471 4 10
+11 1471 5 10
+11 665 1 5
+11 665 2 5
+11 665 3 5
+11 665 4 5
+11 665 5 5
+11 345 1 12
+11 345 2 12
+11 345 3 12
+11 345 4 12
+11 345 5 12
+11 506 1 5
+11 506 2 5
+11 506 3 5
+11 506 4 5
+11 506 5 5
+11 1443 1 14
+11 1443 2 14
+11 1443 3 14
+11 1443 4 14
+11 1443 5 14
+11 1126 1 10
+11 1126 2 10
+11 1126 3 10
+11 1126 4 10
+11 1126 5 10
+11 691 1 12
+11 691 2 12
+11 691 3 12
+11 691 4 12
+11 691 5 12
+11 91 1 13
+11 91 2 13
+11 91 3 13
+11 91 4 13
+11 91 5 13
+12 2730 1 8
+12 2730 2 8
+12 2730 3 8
+12 2730 4 8
+12 2730 5 8
+12 2246 1 2
+12 2246 2 2
+12 2246 3 2
+12 2246 4 2
+12 2246 5 2
+12 3903 1 12
+12 3903 2 12
+12 3903 3 12
+12 3903 4 12
+12 3903 5 12
+12 811 1 1
+12 811 2 1
+12 811 3 1
+12 811 4 1
+12 811 5 1
+12 3489 1 5
+12 3489 2 5
+12 3489 3 5
+12 3489 4 5
+12 3489 5 5
+12 918 1 6
+12 918 2 6
+12 918 3 6
+12 918 4 6
+12 918 5 6
+12 2536 1 9
+12 2536 2 9
+12 2536 3 9
+12 2536 4 9
+12 2536 5 9
+12 126 1 10
+12 126 2 10
+12 126 3 10
+12 126 4 10
+12 126 5 10
+12 102 1 6
+12 102 2 6
+12 102 3 6
+12 102 4 6
+12 102 5 6
+12 3157 1 8
+12 3157 2 8
+12 3157 3 8
+12 3157 4 8
+12 3157 5 8
+12 2042 1 14
+12 2042 2 14
+12 2042 3 14
+12 2042 4 14
+12 2042 5 14
+12 509 1 17
+12 509 2 17
+12 509 3 17
+12 509 4 17
+12 509 5 17
+12 1445 1 4
+12 1445 2 4
+12 1445 3 4
+12 1445 4 4
+12 1445 5 4
+12 1146 1 5
+12 1146 2 5
+12 1146 3 5
+12 1146 4 5
+12 1146 5 5
+12 1373 1 12
+12 1373 2 12
+12 1373 3 12
+12 1373 4 12
+12 1373 5 12
+12 1513 1 15
+12 1513 2 15
+12 1513 3 15
+12 1513 4 15
+12 1513 5 15
+12 3105 1 7
+12 3105 2 7
+12 3105 3 7
+12 3105 4 7
+12 3105 5 7
+12 2481 1 12
+12 2481 2 12
+12 2481 3 12
+12 2481 4 12
+12 2481 5 12
+12 1869 1 6
+12 1869 2 6
+12 1869 3 6
+12 1869 4 6
+12 1869 5 6
+12 1527 1 12
+12 1527 2 12
+12 1527 3 12
+12 1527 4 12
+12 1527 5 12
+12 3375 1 4
+12 3375 2 4
+12 3375 3 4
+12 3375 4 4
+12 3375 5 4
+12 2135 1 12
+12 2135 2 12
+12 2135 3 12
+12 2135 4 12
+12 2135 5 12
+12 729 1 7
+12 729 2 7
+12 729 3 7
+12 729 4 7
+12 729 5 7
+12 464 1 17
+12 464 2 17
+12 464 3 17
+12 464 4 17
+12 464 5 17
+12 2872 1 12
+12 2872 2 12
+12 2872 3 12
+12 2872 4 12
+12 2872 5 12
+12 3583 1 15
+12 3583 2 15
+12 3583 3 15
+12 3583 4 15
+12 3583 5 15
+12 869 1 2
+12 869 2 2
+12 869 3 2
+12 869 4 2
+12 869 5 2
+12 2447 1 1
+12 2447 2 1
+12 2447 3 1
+12 2447 4 1
+12 2447 5 1
+12 59 1 1
+12 59 2 1
+12 59 3 1
+12 59 4 1
+12 59 5 1
+12 3055 1 9
+12 3055 2 9
+12 3055 3 9
+12 3055 4 9
+12 3055 5 9
+12 296 1 3
+12 296 2 3
+12 296 3 3
+12 296 4 3
+12 296 5 3
+12 2118 1 10
+12 2118 2 10
+12 2118 3 10
+12 2118 4 10
+12 2118 5 10
+12 3144 1 6
+12 3144 2 6
+12 3144 3 6
+12 3144 4 6
+12 3144 5 6
+12 2467 1 8
+12 2467 2 8
+12 2467 3 8
+12 2467 4 8
+12 2467 5 8
+12 1967 1 3
+12 1967 2 3
+12 1967 3 3
+12 1967 4 3
+12 1967 5 3
+12 3705 1 8
+12 3705 2 8
+12 3705 3 8
+12 3705 4 8
+12 3705 5 8
+12 1030 1 14
+12 1030 2 14
+12 1030 3 14
+12 1030 4 14
+12 1030 5 14
+12 1865 1 9
+12 1865 2 9
+12 1865 3 9
+12 1865 4 9
+12 1865 5 9
+12 3160 1 4
+12 3160 2 4
+12 3160 3 4
+12 3160 4 4
+12 3160 5 4
+12 3232 1 12
+12 3232 2 12
+12 3232 3 12
+12 3232 4 12
+12 3232 5 12
+12 3886 1 4
+12 3886 2 4
+12 3886 3 4
+12 3886 4 4
+12 3886 5 4
+12 68 1 6
+12 68 2 6
+12 68 3 6
+12 68 4 6
+12 68 5 6
+12 1240 1 4
+12 1240 2 4
+12 1240 3 4
+12 1240 4 4
+12 1240 5 4
+12 3498 1 9
+12 3498 2 9
+12 3498 3 9
+12 3498 4 9
+12 3498 5 9
+12 1805 1 8
+12 1805 2 8
+12 1805 3 8
+12 1805 4 8
+12 1805 5 8
+12 3498 1 9
+12 3498 2 9
+12 3498 3 9
+12 3498 4 9
+12 3498 5 9
+12 3510 1 1
+12 3510 2 1
+12 3510 3 1
+12 3510 4 1
+12 3510 5 1
+12 373 1 10
+12 373 2 10
+12 373 3 10
+12 373 4 10
+12 373 5 10
+12 1286 1 15
+12 1286 2 15
+12 1286 3 15
+12 1286 4 15
+12 1286 5 15
+12 2246 1 2
+12 2246 2 2
+12 2246 3 2
+12 2246 4 2
+12 2246 5 2
+12 205 1 5
+12 205 2 5
+12 205 3 5
+12 205 4 5
+12 205 5 5
+12 1879 1 0
+12 1879 2 0
+12 1879 3 0
+12 1879 4 0
+12 1879 5 0
+12 270 1 13
+12 270 2 13
+12 270 3 13
+12 270 4 13
+12 270 5 13
+12 3478 1 8
+12 3478 2 8
+12 3478 3 8
+12 3478 4 8
+12 3478 5 8
+12 3022 1 14
+12 3022 2 14
+12 3022 3 14
+12 3022 4 14
+12 3022 5 14
+12 2200 1 0
+12 2200 2 0
+12 2200 3 0
+12 2200 4 0
+12 2200 5 0
+12 46 1 5
+12 46 2 5
+12 46 3 5
+12 46 4 5
+12 46 5 5
+12 3405 1 1
+12 3405 2 1
+12 3405 3 1
+12 3405 4 1
+12 3405 5 1
+12 1724 1 4
+12 1724 2 4
+12 1724 3 4
+12 1724 4 4
+12 1724 5 4
+12 757 1 7
+12 757 2 7
+12 757 3 7
+12 757 4 7
+12 757 5 7
+12 773 1 8
+12 773 2 8
+12 773 3 8
+12 773 4 8
+12 773 5 8
+12 211 1 3
+12 211 2 3
+12 211 3 3
+12 211 4 3
+12 211 5 3
+12 2670 1 12
+12 2670 2 12
+12 2670 3 12
+12 2670 4 12
+12 2670 5 12
+12 799 1 6
+12 799 2 6
+12 799 3 6
+12 799 4 6
+12 799 5 6
+13 893 1 6
+13 893 2 6
+13 893 3 6
+13 893 4 6
+13 893 5 6
+13 380 1 12
+13 380 2 12
+13 380 3 12
+13 380 4 12
+13 380 5 12
+13 4122 1 12
+13 4122 2 12
+13 4122 3 12
+13 4122 4 12
+13 4122 5 12
+13 5157 1 14
+13 5157 2 14
+13 5157 3 14
+13 5157 4 14
+13 5157 5 14
+13 5480 1 15
+13 5480 2 15
+13 5480 3 15
+13 5480 4 15
+13 5480 5 15
+13 5574 1 17
+13 5574 2 17
+13 5574 3 17
+13 5574 4 17
+13 5574 5 17
+13 2420 1 6
+13 2420 2 6
+13 2420 3 6
+13 2420 4 6
+13 2420 5 6
+13 7282 1 7
+13 7282 2 7
+13 7282 3 7
+13 7282 4 7
+13 7282 5 7
+13 4528 1 3
+13 4528 2 3
+13 4528 3 3
+13 4528 4 3
+13 4528 5 3
+13 637 1 6
+13 637 2 6
+13 637 3 6
+13 637 4 6
+13 637 5 6
+13 2363 1 9
+13 2363 2 9
+13 2363 3 9
+13 2363 4 9
+13 2363 5 9
+13 99 1 2
+13 99 2 2
+13 99 3 2
+13 99 4 2
+13 99 5 2
+13 1892 1 9
+13 1892 2 9
+13 1892 3 9
+13 1892 4 9
+13 1892 5 9
+13 231 1 2
+13 231 2 2
+13 231 3 2
+13 231 4 2
+13 231 5 2
+13 2672 1 15
+13 2672 2 15
+13 2672 3 15
+13 2672 4 15
+13 2672 5 15
+13 4991 1 2
+13 4991 2 2
+13 4991 3 2
+13 4991 4 2
+13 4991 5 2
+13 2715 1 15
+13 2715 2 15
+13 2715 3 15
+13 2715 4 15
+13 2715 5 15
+13 239 1 3
+13 239 2 3
+13 239 3 3
+13 239 4 3
+13 239 5 3
+13 6492 1 7
+13 6492 2 7
+13 6492 3 7
+13 6492 4 7
+13 6492 5 7
+13 1587 1 9
+13 1587 2 9
+13 1587 3 9
+13 1587 4 9
+13 1587 5 9
+13 4333 1 5
+13 4333 2 5
+13 4333 3 5
+13 4333 4 5
+13 4333 5 5
+13 6561 1 5
+13 6561 2 5
+13 6561 3 5
+13 6561 4 5
+13 6561 5 5
+13 6154 1 8
+13 6154 2 8
+13 6154 3 8
+13 6154 4 8
+13 6154 5 8
+13 7759 1 7
+13 7759 2 7
+13 7759 3 7
+13 7759 4 7
+13 7759 5 7
+13 7672 1 0
+13 7672 2 0
+13 7672 3 0
+13 7672 4 0
+13 7672 5 0
+13 2481 1 12
+13 2481 2 12
+13 2481 3 12
+13 2481 4 12
+13 2481 5 12
+13 4808 1 4
+13 4808 2 4
+13 4808 3 4
+13 4808 4 4
+13 4808 5 4
+13 8071 1 6
+13 8071 2 6
+13 8071 3 6
+13 8071 4 6
+13 8071 5 6
+13 8156 1 10
+13 8156 2 10
+13 8156 3 10
+13 8156 4 10
+13 8156 5 10
+13 2037 1 12
+13 2037 2 12
+13 2037 3 12
+13 2037 4 12
+13 2037 5 12
+13 1194 1 6
+13 1194 2 6
+13 1194 3 6
+13 1194 4 6
+13 1194 5 6
+13 1011 1 7
+13 1011 2 7
+13 1011 3 7
+13 1011 4 7
+13 1011 5 7
+13 7104 1 9
+13 7104 2 9
+13 7104 3 9
+13 7104 4 9
+13 7104 5 9
+13 999 1 13
+13 999 2 13
+13 999 3 13
+13 999 4 13
+13 999 5 13
+13 3079 1 10
+13 3079 2 10
+13 3079 3 10
+13 3079 4 10
+13 3079 5 10
+13 1167 1 15
+13 1167 2 15
+13 1167 3 15
+13 1167 4 15
+13 1167 5 15
+13 2635 1 6
+13 2635 2 6
+13 2635 3 6
+13 2635 4 6
+13 2635 5 6
+13 5668 1 0
+13 5668 2 0
+13 5668 3 0
+13 5668 4 0
+13 5668 5 0
+13 3834 1 9
+13 3834 2 9
+13 3834 3 9
+13 3834 4 9
+13 3834 5 9
+13 4540 1 10
+13 4540 2 10
+13 4540 3 10
+13 4540 4 10
+13 4540 5 10
+13 1067 1 14
+13 1067 2 14
+13 1067 3 14
+13 1067 4 14
+13 1067 5 14
+13 239 1 3
+13 239 2 3
+13 239 3 3
+13 239 4 3
+13 239 5 3
+13 4066 1 15
+13 4066 2 15
+13 4066 3 15
+13 4066 4 15
+13 4066 5 15
+13 7101 1 12
+13 7101 2 12
+13 7101 3 12
+13 7101 4 12
+13 7101 5 12
+13 7826 1 3
+13 7826 2 3
+13 7826 3 3
+13 7826 4 3
+13 7826 5 3
+13 174 1 6
+13 174 2 6
+13 174 3 6
+13 174 4 6
+13 174 5 6
+13 4578 1 14
+13 4578 2 14
+13 4578 3 14
+13 4578 4 14
+13 4578 5 14
+13 2875 1 1
+13 2875 2 1
+13 2875 3 1
+13 2875 4 1
+13 2875 5 1
+13 6067 1 10
+13 6067 2 10
+13 6067 3 10
+13 6067 4 10
+13 6067 5 10
+13 3180 1 2
+13 3180 2 2
+13 3180 3 2
+13 3180 4 2
+13 3180 5 2
+13 3426 1 6
+13 3426 2 6
+13 3426 3 6
+13 3426 4 6
+13 3426 5 6
+13 2498 1 8
+13 2498 2 8
+13 2498 3 8
+13 2498 4 8
+13 2498 5 8
+13 4938 1 6
+13 4938 2 6
+13 4938 3 6
+13 4938 4 6
+13 4938 5 6
+13 1622 1 10
+13 1622 2 10
+13 1622 3 10
+13 1622 4 10
+13 1622 5 10
+13 5260 1 9
+13 5260 2 9
+13 5260 3 9
+13 5260 4 9
+13 5260 5 9
+13 6721 1 17
+13 6721 2 17
+13 6721 3 17
+13 6721 4 17
+13 6721 5 17
+13 1809 1 3
+13 1809 2 3
+13 1809 3 3
+13 1809 4 3
+13 1809 5 3
+13 7230 1 14
+13 7230 2 14
+13 7230 3 14
+13 7230 4 14
+13 7230 5 14
+13 2000 1 8
+13 2000 2 8
+13 2000 3 8
+13 2000 4 8
+13 2000 5 8
+13 398 1 6
+13 398 2 6
+13 398 3 6
+13 398 4 6
+13 398 5 6
+13 5964 1 9
+13 5964 2 9
+13 5964 3 9
+13 5964 4 9
+13 5964 5 9
+13 6171 1 15
+13 6171 2 15
+13 6171 3 15
+13 6171 4 15
+13 6171 5 15
+13 6752 1 2
+13 6752 2 2
+13 6752 3 2
+13 6752 4 2
+13 6752 5 2
+13 7904 1 6
+13 7904 2 6
+13 7904 3 6
+13 7904 4 6
+13 7904 5 6
+14 2306 1 6
+14 2306 2 6
+14 2306 3 6
+14 2306 4 6
+14 2306 5 6
+14 1881 1 7
+14 1881 2 7
+14 1881 3 7
+14 1881 4 7
+14 1881 5 7
+14 11659 1 4
+14 11659 2 4
+14 11659 3 4
+14 11659 4 4
+14 11659 5 4
+14 12598 1 3
+14 12598 2 3
+14 12598 3 3
+14 12598 4 3
+14 12598 5 3
+14 15891 1 9
+14 15891 2 9
+14 15891 3 9
+14 15891 4 9
+14 15891 5 9
+14 7988 1 15
+14 7988 2 15
+14 7988 3 15
+14 7988 4 15
+14 7988 5 15
+14 2768 1 2
+14 2768 2 2
+14 2768 3 2
+14 2768 4 2
+14 2768 5 2
+14 2197 1 13
+14 2197 2 13
+14 2197 3 13
+14 2197 4 13
+14 2197 5 13
+14 15826 1 10
+14 15826 2 10
+14 15826 3 10
+14 15826 4 10
+14 15826 5 10
+14 4100 1 1
+14 4100 2 1
+14 4100 3 1
+14 4100 4 1
+14 4100 5 1
+14 5497 1 8
+14 5497 2 8
+14 5497 3 8
+14 5497 4 8
+14 5497 5 8
+14 1329 1 14
+14 1329 2 14
+14 1329 3 14
+14 1329 4 14
+14 1329 5 14
+14 4648 1 7
+14 4648 2 7
+14 4648 3 7
+14 4648 4 7
+14 4648 5 7
+14 11168 1 13
+14 11168 2 13
+14 11168 3 13
+14 11168 4 13
+14 11168 5 13
+14 2871 1 0
+14 2871 2 0
+14 2871 3 0
+14 2871 4 0
+14 2871 5 0
+14 6846 1 2
+14 6846 2 2
+14 6846 3 2
+14 6846 4 2
+14 6846 5 2
+14 7982 1 15
+14 7982 2 15
+14 7982 3 15
+14 7982 4 15
+14 7982 5 15
+14 2869 1 10
+14 2869 2 10
+14 2869 3 10
+14 2869 4 10
+14 2869 5 10
+14 13103 1 3
+14 13103 2 3
+14 13103 3 3
+14 13103 4 3
+14 13103 5 3
+14 9600 1 14
+14 9600 2 14
+14 9600 3 14
+14 9600 4 14
+14 9600 5 14
+14 13746 1 9
+14 13746 2 9
+14 13746 3 9
+14 13746 4 9
+14 13746 5 9
+14 9665 1 6
+14 9665 2 6
+14 9665 3 6
+14 9665 4 6
+14 9665 5 6
+14 6264 1 15
+14 6264 2 15
+14 6264 3 15
+14 6264 4 15
+14 6264 5 15
+14 10450 1 3
+14 10450 2 3
+14 10450 3 3
+14 10450 4 3
+14 10450 5 3
+14 13753 1 14
+14 13753 2 14
+14 13753 3 14
+14 13753 4 14
+14 13753 5 14
+14 13977 1 6
+14 13977 2 6
+14 13977 3 6
+14 13977 4 6
+14 13977 5 6
+14 5279 1 17
+14 5279 2 17
+14 5279 3 17
+14 5279 4 17
+14 5279 5 17
+14 7584 1 15
+14 7584 2 15
+14 7584 3 15
+14 7584 4 15
+14 7584 5 15
+14 247 1 17
+14 247 2 17
+14 247 3 17
+14 247 4 17
+14 247 5 17
+14 13284 1 7
+14 13284 2 7
+14 13284 3 7
+14 13284 4 7
+14 13284 5 7
+14 10789 1 6
+14 10789 2 6
+14 10789 3 6
+14 10789 4 6
+14 10789 5 6
+14 4332 1 3
+14 4332 2 3
+14 4332 3 3
+14 4332 4 3
+14 4332 5 3
+14 15705 1 13
+14 15705 2 13
+14 15705 3 13
+14 15705 4 13
+14 15705 5 13
+14 5405 1 8
+14 5405 2 8
+14 5405 3 8
+14 5405 4 8
+14 5405 5 8
+14 12031 1 14
+14 12031 2 14
+14 12031 3 14
+14 12031 4 14
+14 12031 5 14
+14 4684 1 15
+14 4684 2 15
+14 4684 3 15
+14 4684 4 15
+14 4684 5 15
+14 10107 1 14
+14 10107 2 14
+14 10107 3 14
+14 10107 4 14
+14 10107 5 14
+14 10645 1 4
+14 10645 2 4
+14 10645 3 4
+14 10645 4 4
+14 10645 5 4
+14 1814 1 8
+14 1814 2 8
+14 1814 3 8
+14 1814 4 8
+14 1814 5 8
+14 12906 1 0
+14 12906 2 0
+14 12906 3 0
+14 12906 4 0
+14 12906 5 0
+14 13619 1 5
+14 13619 2 5
+14 13619 3 5
+14 13619 4 5
+14 13619 5 5
+14 16110 1 3
+14 16110 2 3
+14 16110 3 3
+14 16110 4 3
+14 16110 5 3
+14 11973 1 12
+14 11973 2 12
+14 11973 3 12
+14 11973 4 12
+14 11973 5 12
+14 4483 1 13
+14 4483 2 13
+14 4483 3 13
+14 4483 4 13
+14 4483 5 13
+14 2052 1 1
+14 2052 2 1
+14 2052 3 1
+14 2052 4 1
+14 2052 5 1
+14 6049 1 7
+14 6049 2 7
+14 6049 3 7
+14 6049 4 7
+14 6049 5 7
+14 5470 1 17
+14 5470 2 17
+14 5470 3 17
+14 5470 4 17
+14 5470 5 17
+14 15849 1 4
+14 15849 2 4
+14 15849 3 4
+14 15849 4 4
+14 15849 5 4
+14 12203 1 0
+14 12203 2 0
+14 12203 3 0
+14 12203 4 0
+14 12203 5 0
+14 12665 1 12
+14 12665 2 12
+14 12665 3 12
+14 12665 4 12
+14 12665 5 12
+14 1957 1 7
+14 1957 2 7
+14 1957 3 7
+14 1957 4 7
+14 1957 5 7
+14 8833 1 17
+14 8833 2 17
+14 8833 3 17
+14 8833 4 17
+14 8833 5 17
+14 15511 1 13
+14 15511 2 13
+14 15511 3 13
+14 15511 4 13
+14 15511 5 13
+14 7190 1 6
+14 7190 2 6
+14 7190 3 6
+14 7190 4 6
+14 7190 5 6
+14 10835 1 17
+14 10835 2 17
+14 10835 3 17
+14 10835 4 17
+14 10835 5 17
+14 1350 1 2
+14 1350 2 2
+14 1350 3 2
+14 1350 4 2
+14 1350 5 2
+14 8808 1 7
+14 8808 2 7
+14 8808 3 7
+14 8808 4 7
+14 8808 5 7
+14 8043 1 13
+14 8043 2 13
+14 8043 3 13
+14 8043 4 13
+14 8043 5 13
+14 1172 1 14
+14 1172 2 14
+14 1172 3 14
+14 1172 4 14
+14 1172 5 14
+14 5572 1 17
+14 5572 2 17
+14 5572 3 17
+14 5572 4 17
+14 5572 5 17
+14 10871 1 1
+14 10871 2 1
+14 10871 3 1
+14 10871 4 1
+14 10871 5 1
+14 12865 1 6
+14 12865 2 6
+14 12865 3 6
+14 12865 4 6
+14 12865 5 6
+14 6793 1 17
+14 6793 2 17
+14 6793 3 17
+14 6793 4 17
+14 6793 5 17
+14 2973 1 5
+14 2973 2 5
+14 2973 3 5
+14 2973 4 5
+14 2973 5 5
+15 20950 1 7
+15 20950 2 7
+15 20950 3 7
+15 20950 4 7
+15 20950 5 7
+15 4112 1 6
+15 4112 2 6
+15 4112 3 6
+15 4112 4 6
+15 4112 5 6
+15 20069 1 1
+15 20069 2 1
+15 20069 3 1
+15 20069 4 1
+15 20069 5 1
+15 21040 1 17
+15 21040 2 17
+15 21040 3 17
+15 21040 4 17
+15 21040 5 17
+15 1498 1 0
+15 1498 2 0
+15 1498 3 0
+15 1498 4 0
+15 1498 5 0
+15 4453 1 3
+15 4453 2 3
+15 4453 3 3
+15 4453 4 3
+15 4453 5 3
+15 27228 1 17
+15 27228 2 17
+15 27228 3 17
+15 27228 4 17
+15 27228 5 17
+15 9353 1 2
+15 9353 2 2
+15 9353 3 2
+15 9353 4 2
+15 9353 5 2
+15 12060 1 5
+15 12060 2 5
+15 12060 3 5
+15 12060 4 5
+15 12060 5 5
+15 30253 1 15
+15 30253 2 15
+15 30253 3 15
+15 30253 4 15
+15 30253 5 15
+15 9914 1 4
+15 9914 2 4
+15 9914 3 4
+15 9914 4 4
+15 9914 5 4
+15 9111 1 17
+15 9111 2 17
+15 9111 3 17
+15 9111 4 17
+15 9111 5 17
+15 9191 1 13
+15 9191 2 13
+15 9191 3 13
+15 9191 4 13
+15 9191 5 13
+15 2061 1 15
+15 2061 2 15
+15 2061 3 15
+15 2061 4 15
+15 2061 5 15
+15 16458 1 7
+15 16458 2 7
+15 16458 3 7
+15 16458 4 7
+15 16458 5 7
+15 14420 1 17
+15 14420 2 17
+15 14420 3 17
+15 14420 4 17
+15 14420 5 17
+15 11687 1 4
+15 11687 2 4
+15 11687 3 4
+15 11687 4 4
+15 11687 5 4
+15 12915 1 14
+15 12915 2 14
+15 12915 3 14
+15 12915 4 14
+15 12915 5 14
+15 30014 1 5
+15 30014 2 5
+15 30014 3 5
+15 30014 4 5
+15 30014 5 5
+15 17852 1 8
+15 17852 2 8
+15 17852 3 8
+15 17852 4 8
+15 17852 5 8
+15 18801 1 1
+15 18801 2 1
+15 18801 3 1
+15 18801 4 1
+15 18801 5 1
+15 30476 1 10
+15 30476 2 10
+15 30476 3 10
+15 30476 4 10
+15 30476 5 10
+15 19880 1 10
+15 19880 2 10
+15 19880 3 10
+15 19880 4 10
+15 19880 5 10
+15 25937 1 13
+15 25937 2 13
+15 25937 3 13
+15 25937 4 13
+15 25937 5 13
+15 30840 1 17
+15 30840 2 17
+15 30840 3 17
+15 30840 4 17
+15 30840 5 17
+15 29260 1 4
+15 29260 2 4
+15 29260 3 4
+15 29260 4 4
+15 29260 5 4
+15 29698 1 3
+15 29698 2 3
+15 29698 3 3
+15 29698 4 3
+15 29698 5 3
+15 13207 1 12
+15 13207 2 12
+15 13207 3 12
+15 13207 4 12
+15 13207 5 12
+15 8345 1 15
+15 8345 2 15
+15 8345 3 15
+15 8345 4 15
+15 8345 5 15
+15 28649 1 0
+15 28649 2 0
+15 28649 3 0
+15 28649 4 0
+15 28649 5 0
+15 7591 1 3
+15 7591 2 3
+15 7591 3 3
+15 7591 4 3
+15 7591 5 3
+15 11417 1 4
+15 11417 2 4
+15 11417 3 4
+15 11417 4 4
+15 11417 5 4
+15 31952 1 3
+15 31952 2 3
+15 31952 3 3
+15 31952 4 3
+15 31952 5 3
+15 3936 1 5
+15 3936 2 5
+15 3936 3 5
+15 3936 4 5
+15 3936 5 5
+15 855 1 5
+15 855 2 5
+15 855 3 5
+15 855 4 5
+15 855 5 5
+15 6242 1 15
+15 6242 2 15
+15 6242 3 15
+15 6242 4 15
+15 6242 5 15
+15 7617 1 5
+15 7617 2 5
+15 7617 3 5
+15 7617 4 5
+15 7617 5 5
+15 30831 1 12
+15 30831 2 12
+15 30831 3 12
+15 30831 4 12
+15 30831 5 12
+15 27063 1 4
+15 27063 2 4
+15 27063 3 4
+15 27063 4 4
+15 27063 5 4
+15 1925 1 15
+15 1925 2 15
+15 1925 3 15
+15 1925 4 15
+15 1925 5 15
+15 31280 1 0
+15 31280 2 0
+15 31280 3 0
+15 31280 4 0
+15 31280 5 0
+15 8089 1 2
+15 8089 2 2
+15 8089 3 2
+15 8089 4 2
+15 8089 5 2
+15 14799 1 13
+15 14799 2 13
+15 14799 3 13
+15 14799 4 13
+15 14799 5 13
+15 24470 1 3
+15 24470 2 3
+15 24470 3 3
+15 24470 4 3
+15 24470 5 3
+15 3977 1 13
+15 3977 2 13
+15 3977 3 13
+15 3977 4 13
+15 3977 5 13
+15 6822 1 3
+15 6822 2 3
+15 6822 3 3
+15 6822 4 3
+15 6822 5 3
+15 10634 1 1
+15 10634 2 1
+15 10634 3 1
+15 10634 4 1
+15 10634 5 1
+15 30639 1 3
+15 30639 2 3
+15 30639 3 3
+15 30639 4 3
+15 30639 5 3
+15 4697 1 3
+15 4697 2 3
+15 4697 3 3
+15 4697 4 3
+15 4697 5 3
+15 1311 1 1
+15 1311 2 1
+15 1311 3 1
+15 1311 4 1
+15 1311 5 1
+15 29753 1 6
+15 29753 2 6
+15 29753 3 6
+15 29753 4 6
+15 29753 5 6
+15 17644 1 14
+15 17644 2 14
+15 17644 3 14
+15 17644 4 14
+15 17644 5 14
+15 11986 1 9
+15 11986 2 9
+15 11986 3 9
+15 11986 4 9
+15 11986 5 9
+15 29910 1 0
+15 29910 2 0
+15 29910 3 0
+15 29910 4 0
+15 29910 5 0
+15 8977 1 9
+15 8977 2 9
+15 8977 3 9
+15 8977 4 9
+15 8977 5 9
+15 5871 1 1
+15 5871 2 1
+15 5871 3 1
+15 5871 4 1
+15 5871 5 1
+15 22859 1 6
+15 22859 2 6
+15 22859 3 6
+15 22859 4 6
+15 22859 5 6
+15 32348 1 5
+15 32348 2 5
+15 32348 3 5
+15 32348 4 5
+15 32348 5 5
+15 26024 1 2
+15 26024 2 2
+15 26024 3 2
+15 26024 4 2
+15 26024 5 2
+15 25693 1 0
+15 25693 2 0
+15 25693 3 0
+15 25693 4 0
+15 25693 5 0
+15 11966 1 4
+15 11966 2 4
+15 11966 3 4
+15 11966 4 4
+15 11966 5 4
+15 18826 1 14
+15 18826 2 14
+15 18826 3 14
+15 18826 4 14
+15 18826 5 14
+15 31356 1 10
+15 31356 2 10
+15 31356 3 10
+15 31356 4 10
+15 31356 5 10
+15 10078 1 14
+15 10078 2 14
+15 10078 3 14
+15 10078 4 14
+15 10078 5 14
+16 58244 1 14
+16 58244 2 14
+16 58244 3 14
+16 58244 4 14
+16 58244 5 14
+16 25812 1 9
+16 25812 2 9
+16 25812 3 9
+16 25812 4 9
+16 25812 5 9
+16 5981 1 6
+16 5981 2 6
+16 5981 3 6
+16 5981 4 6
+16 5981 5 6
+16 38854 1 14
+16 38854 2 14
+16 38854 3 14
+16 38854 4 14
+16 38854 5 14
+16 29656 1 15
+16 29656 2 15
+16 29656 3 15
+16 29656 4 15
+16 29656 5 15
+16 50754 1 13
+16 50754 2 13
+16 50754 3 13
+16 50754 4 13
+16 50754 5 13
+16 5784 1 13
+16 5784 2 13
+16 5784 3 13
+16 5784 4 13
+16 5784 5 13
+16 61887 1 13
+16 61887 2 13
+16 61887 3 13
+16 61887 4 13
+16 61887 5 13
+16 48214 1 9
+16 48214 2 9
+16 48214 3 9
+16 48214 4 9
+16 48214 5 9
+16 12266 1 2
+16 12266 2 2
+16 12266 3 2
+16 12266 4 2
+16 12266 5 2
+16 38129 1 5
+16 38129 2 5
+16 38129 3 5
+16 38129 4 5
+16 38129 5 5
+16 28380 1 6
+16 28380 2 6
+16 28380 3 6
+16 28380 4 6
+16 28380 5 6
+16 50376 1 1
+16 50376 2 1
+16 50376 3 1
+16 50376 4 1
+16 50376 5 1
+16 51343 1 3
+16 51343 2 3
+16 51343 3 3
+16 51343 4 3
+16 51343 5 3
+16 10060 1 13
+16 10060 2 13
+16 10060 3 13
+16 10060 4 13
+16 10060 5 13
+16 6542 1 2
+16 6542 2 2
+16 6542 3 2
+16 6542 4 2
+16 6542 5 2
+16 9936 1 8
+16 9936 2 8
+16 9936 3 8
+16 9936 4 8
+16 9936 5 8
+16 52971 1 15
+16 52971 2 15
+16 52971 3 15
+16 52971 4 15
+16 52971 5 15
+16 48546 1 12
+16 48546 2 12
+16 48546 3 12
+16 48546 4 12
+16 48546 5 12
+16 8054 1 2
+16 8054 2 2
+16 8054 3 2
+16 8054 4 2
+16 8054 5 2
+16 62559 1 15
+16 62559 2 15
+16 62559 3 15
+16 62559 4 15
+16 62559 5 15
+16 9259 1 14
+16 9259 2 14
+16 9259 3 14
+16 9259 4 14
+16 9259 5 14
+16 29059 1 3
+16 29059 2 3
+16 29059 3 3
+16 29059 4 3
+16 29059 5 3
+16 33772 1 5
+16 33772 2 5
+16 33772 3 5
+16 33772 4 5
+16 33772 5 5
+16 60991 1 6
+16 60991 2 6
+16 60991 3 6
+16 60991 4 6
+16 60991 5 6
+16 42607 1 3
+16 42607 2 3
+16 42607 3 3
+16 42607 4 3
+16 42607 5 3
+16 42127 1 13
+16 42127 2 13
+16 42127 3 13
+16 42127 4 13
+16 42127 5 13
+16 41593 1 7
+16 41593 2 7
+16 41593 3 7
+16 41593 4 7
+16 41593 5 7
+16 2699 1 1
+16 2699 2 1
+16 2699 3 1
+16 2699 4 1
+16 2699 5 1
+16 23372 1 17
+16 23372 2 17
+16 23372 3 17
+16 23372 4 17
+16 23372 5 17
+16 28412 1 9
+16 28412 2 9
+16 28412 3 9
+16 28412 4 9
+16 28412 5 9
+16 33117 1 14
+16 33117 2 14
+16 33117 3 14
+16 33117 4 14
+16 33117 5 14
+16 19250 1 13
+16 19250 2 13
+16 19250 3 13
+16 19250 4 13
+16 19250 5 13
+16 27209 1 7
+16 27209 2 7
+16 27209 3 7
+16 27209 4 7
+16 27209 5 7
+16 24083 1 8
+16 24083 2 8
+16 24083 3 8
+16 24083 4 8
+16 24083 5 8
+16 62474 1 3
+16 62474 2 3
+16 62474 3 3
+16 62474 4 3
+16 62474 5 3
+16 58487 1 15
+16 58487 2 15
+16 58487 3 15
+16 58487 4 15
+16 58487 5 15
+16 59237 1 2
+16 59237 2 2
+16 59237 3 2
+16 59237 4 2
+16 59237 5 2
+16 33459 1 4
+16 33459 2 4
+16 33459 3 4
+16 33459 4 4
+16 33459 5 4
+16 36262 1 13
+16 36262 2 13
+16 36262 3 13
+16 36262 4 13
+16 36262 5 13
+16 45939 1 8
+16 45939 2 8
+16 45939 3 8
+16 45939 4 8
+16 45939 5 8
+16 28047 1 17
+16 28047 2 17
+16 28047 3 17
+16 28047 4 17
+16 28047 5 17
+16 53197 1 5
+16 53197 2 5
+16 53197 3 5
+16 53197 4 5
+16 53197 5 5
+16 25485 1 17
+16 25485 2 17
+16 25485 3 17
+16 25485 4 17
+16 25485 5 17
+16 1170 1 7
+16 1170 2 7
+16 1170 3 7
+16 1170 4 7
+16 1170 5 7
+16 35117 1 0
+16 35117 2 0
+16 35117 3 0
+16 35117 4 0
+16 35117 5 0
+16 51430 1 3
+16 51430 2 3
+16 51430 3 3
+16 51430 4 3
+16 51430 5 3
+16 40909 1 8
+16 40909 2 8
+16 40909 3 8
+16 40909 4 8
+16 40909 5 8
+16 43538 1 7
+16 43538 2 7
+16 43538 3 7
+16 43538 4 7
+16 43538 5 7
+16 62102 1 14
+16 62102 2 14
+16 62102 3 14
+16 62102 4 14
+16 62102 5 14
+16 32920 1 17
+16 32920 2 17
+16 32920 3 17
+16 32920 4 17
+16 32920 5 17
+16 58281 1 15
+16 58281 2 15
+16 58281 3 15
+16 58281 4 15
+16 58281 5 15
+16 25223 1 8
+16 25223 2 8
+16 25223 3 8
+16 25223 4 8
+16 25223 5 8
+16 39064 1 6
+16 39064 2 6
+16 39064 3 6
+16 39064 4 6
+16 39064 5 6
+16 59153 1 3
+16 59153 2 3
+16 59153 3 3
+16 59153 4 3
+16 59153 5 3
+16 31255 1 15
+16 31255 2 15
+16 31255 3 15
+16 31255 4 15
+16 31255 5 15
+16 36698 1 15
+16 36698 2 15
+16 36698 3 15
+16 36698 4 15
+16 36698 5 15
+16 31474 1 2
+16 31474 2 2
+16 31474 3 2
+16 31474 4 2
+16 31474 5 2
+16 26770 1 13
+16 26770 2 13
+16 26770 3 13
+16 26770 4 13
+16 26770 5 13
+16 23106 1 9
+16 23106 2 9
+16 23106 3 9
+16 23106 4 9
+16 23106 5 9
+16 15173 1 1
+16 15173 2 1
+16 15173 3 1
+16 15173 4 1
+16 15173 5 1
+16 21723 1 0
+16 21723 2 0
+16 21723 3 0
+16 21723 4 0
+16 21723 5 0
+16 56305 1 3
+16 56305 2 3
+16 56305 3 3
+16 56305 4 3
+16 56305 5 3
+16 64008 1 14
+16 64008 2 14
+16 64008 3 14
+16 64008 4 14
+16 64008 5 14
+17 93272 1 6
+17 93272 2 6
+17 93272 3 6
+17 93272 4 6
+17 93272 5 6
+17 11659 1 4
+17 11659 2 4
+17 11659 3 4
+17 11659 4 4
+17 11659 5 4
+17 96311 1 5
+17 96311 2 5
+17 96311 3 5
+17 96311 4 5
+17 96311 5 5
+17 63681 1 7
+17 63681 2 7
+17 63681 3 7
+17 63681 4 7
+17 63681 5 7
+17 80799 1 6
+17 80799 2 6
+17 80799 3 6
+17 80799 4 6
+17 80799 5 6
+17 63603 1 1
+17 63603 2 1
+17 63603 3 1
+17 63603 4 1
+17 63603 5 1
+17 112164 1 8
+17 112164 2 8
+17 112164 3 8
+17 112164 4 8
+17 112164 5 8
+17 19891 1 13
+17 19891 2 13
+17 19891 3 13
+17 19891 4 13
+17 19891 5 13
+17 44447 1 5
+17 44447 2 5
+17 44447 3 5
+17 44447 4 5
+17 44447 5 5
+17 71186 1 0
+17 71186 2 0
+17 71186 3 0
+17 71186 4 0
+17 71186 5 0
+17 91697 1 1
+17 91697 2 1
+17 91697 3 1
+17 91697 4 1
+17 91697 5 1
+17 68930 1 7
+17 68930 2 7
+17 68930 3 7
+17 68930 4 7
+17 68930 5 7
+17 22151 1 17
+17 22151 2 17
+17 22151 3 17
+17 22151 4 17
+17 22151 5 17
+17 75004 1 1
+17 75004 2 1
+17 75004 3 1
+17 75004 4 1
+17 75004 5 1
+17 89182 1 8
+17 89182 2 8
+17 89182 3 8
+17 89182 4 8
+17 89182 5 8
+17 14115 1 12
+17 14115 2 12
+17 14115 3 12
+17 14115 4 12
+17 14115 5 12
+17 13641 1 2
+17 13641 2 2
+17 13641 3 2
+17 13641 4 2
+17 13641 5 2
+17 13865 1 1
+17 13865 2 1
+17 13865 3 1
+17 13865 4 1
+17 13865 5 1
+17 81842 1 8
+17 81842 2 8
+17 81842 3 8
+17 81842 4 8
+17 81842 5 8
+17 98226 1 17
+17 98226 2 17
+17 98226 3 17
+17 98226 4 17
+17 98226 5 17
+17 51230 1 3
+17 51230 2 3
+17 51230 3 3
+17 51230 4 3
+17 51230 5 3
+17 13686 1 5
+17 13686 2 5
+17 13686 3 5
+17 13686 4 5
+17 13686 5 5
+17 91828 1 13
+17 91828 2 13
+17 91828 3 13
+17 91828 4 13
+17 91828 5 13
+17 114795 1 13
+17 114795 2 13
+17 114795 3 13
+17 114795 4 13
+17 114795 5 13
+17 12543 1 2
+17 12543 2 2
+17 12543 3 2
+17 12543 4 2
+17 12543 5 2
+17 57890 1 1
+17 57890 2 1
+17 57890 3 1
+17 57890 4 1
+17 57890 5 1
+17 115698 1 13
+17 115698 2 13
+17 115698 3 13
+17 115698 4 13
+17 115698 5 13
+17 63601 1 14
+17 63601 2 14
+17 63601 3 14
+17 63601 4 14
+17 63601 5 14
+17 92716 1 0
+17 92716 2 0
+17 92716 3 0
+17 92716 4 0
+17 92716 5 0
+17 87889 1 13
+17 87889 2 13
+17 87889 3 13
+17 87889 4 13
+17 87889 5 13
+17 123518 1 9
+17 123518 2 9
+17 123518 3 9
+17 123518 4 9
+17 123518 5 9
+17 122122 1 13
+17 122122 2 13
+17 122122 3 13
+17 122122 4 13
+17 122122 5 13
+17 101033 1 7
+17 101033 2 7
+17 101033 3 7
+17 101033 4 7
+17 101033 5 7
+17 9357 1 7
+17 9357 2 7
+17 9357 3 7
+17 9357 4 7
+17 9357 5 7
+17 127595 1 6
+17 127595 2 6
+17 127595 3 6
+17 127595 4 6
+17 127595 5 6
+17 64032 1 2
+17 64032 2 2
+17 64032 3 2
+17 64032 4 2
+17 64032 5 2
+17 72380 1 8
+17 72380 2 8
+17 72380 3 8
+17 72380 4 8
+17 72380 5 8
+17 128576 1 9
+17 128576 2 9
+17 128576 3 9
+17 128576 4 9
+17 128576 5 9
+17 58709 1 14
+17 58709 2 14
+17 58709 3 14
+17 58709 4 14
+17 58709 5 14
+17 90818 1 10
+17 90818 2 10
+17 90818 3 10
+17 90818 4 10
+17 90818 5 10
+17 96369 1 6
+17 96369 2 6
+17 96369 3 6
+17 96369 4 6
+17 96369 5 6
+17 52794 1 2
+17 52794 2 2
+17 52794 3 2
+17 52794 4 2
+17 52794 5 2
+17 105174 1 6
+17 105174 2 6
+17 105174 3 6
+17 105174 4 6
+17 105174 5 6
+17 61857 1 6
+17 61857 2 6
+17 61857 3 6
+17 61857 4 6
+17 61857 5 6
+17 19478 1 3
+17 19478 2 3
+17 19478 3 3
+17 19478 4 3
+17 19478 5 3
+17 117809 1 4
+17 117809 2 4
+17 117809 3 4
+17 117809 4 4
+17 117809 5 4
+17 72978 1 3
+17 72978 2 3
+17 72978 3 3
+17 72978 4 3
+17 72978 5 3
+17 6547 1 0
+17 6547 2 0
+17 6547 3 0
+17 6547 4 0
+17 6547 5 0
+17 68799 1 10
+17 68799 2 10
+17 68799 3 10
+17 68799 4 10
+17 68799 5 10
+17 99900 1 12
+17 99900 2 12
+17 99900 3 12
+17 99900 4 12
+17 99900 5 12
+17 126252 1 12
+17 126252 2 12
+17 126252 3 12
+17 126252 4 12
+17 126252 5 12
+17 83476 1 5
+17 83476 2 5
+17 83476 3 5
+17 83476 4 5
+17 83476 5 5
+17 38083 1 13
+17 38083 2 13
+17 38083 3 13
+17 38083 4 13
+17 38083 5 13
+17 61784 1 13
+17 61784 2 13
+17 61784 3 13
+17 61784 4 13
+17 61784 5 13
+17 24526 1 9
+17 24526 2 9
+17 24526 3 9
+17 24526 4 9
+17 24526 5 9
+17 117696 1 17
+17 117696 2 17
+17 117696 3 17
+17 117696 4 17
+17 117696 5 17
+17 50749 1 10
+17 50749 2 10
+17 50749 3 10
+17 50749 4 10
+17 50749 5 10
+17 55779 1 12
+17 55779 2 12
+17 55779 3 12
+17 55779 4 12
+17 55779 5 12
+17 2470 1 3
+17 2470 2 3
+17 2470 3 3
+17 2470 4 3
+17 2470 5 3
+17 26842 1 2
+17 26842 2 2
+17 26842 3 2
+17 26842 4 2
+17 26842 5 2
+17 16268 1 17
+17 16268 2 17
+17 16268 3 17
+17 16268 4 17
+17 16268 5 17
+17 125988 1 0
+17 125988 2 0
+17 125988 3 0
+17 125988 4 0
+17 125988 5 0
+17 15331 1 1
+17 15331 2 1
+17 15331 3 1
+17 15331 4 1
+17 15331 5 1
+17 87497 1 10
+17 87497 2 10
+17 87497 3 10
+17 87497 4 10
+17 87497 5 10
+18 250333 1 7
+18 250333 2 7
+18 250333 3 7
+18 250333 4 7
+18 250333 5 7
+18 250728 1 3
+18 250728 2 3
+18 250728 3 3
+18 250728 4 3
+18 250728 5 3
+18 218536 1 2
+18 218536 2 2
+18 218536 3 2
+18 218536 4 2
+18 218536 5 2
+18 251345 1 14
+18 251345 2 14
+18 251345 3 14
+18 251345 4 14
+18 251345 5 14
+18 123978 1 2
+18 123978 2 2
+18 123978 3 2
+18 123978 4 2
+18 123978 5 2
+18 25057 1 9
+18 25057 2 9
+18 25057 3 9
+18 25057 4 9
+18 25057 5 9
+18 55168 1 12
+18 55168 2 12
+18 55168 3 12
+18 55168 4 12
+18 55168 5 12
+18 14806 1 10
+18 14806 2 10
+18 14806 3 10
+18 14806 4 10
+18 14806 5 10
+18 252354 1 6
+18 252354 2 6
+18 252354 3 6
+18 252354 4 6
+18 252354 5 6
+18 25497 1 13
+18 25497 2 13
+18 25497 3 13
+18 25497 4 13
+18 25497 5 13
+18 62064 1 15
+18 62064 2 15
+18 62064 3 15
+18 62064 4 15
+18 62064 5 15
+18 209425 1 15
+18 209425 2 15
+18 209425 3 15
+18 209425 4 15
+18 209425 5 15
+18 41291 1 4
+18 41291 2 4
+18 41291 3 4
+18 41291 4 4
+18 41291 5 4
+18 135093 1 5
+18 135093 2 5
+18 135093 3 5
+18 135093 4 5
+18 135093 5 5
+18 245030 1 17
+18 245030 2 17
+18 245030 3 17
+18 245030 4 17
+18 245030 5 17
+18 56931 1 7
+18 56931 2 7
+18 56931 3 7
+18 56931 4 7
+18 56931 5 7
+18 2524 1 8
+18 2524 2 8
+18 2524 3 8
+18 2524 4 8
+18 2524 5 8
+18 196720 1 12
+18 196720 2 12
+18 196720 3 12
+18 196720 4 12
+18 196720 5 12
+18 244100 1 8
+18 244100 2 8
+18 244100 3 8
+18 244100 4 8
+18 244100 5 8
+18 220927 1 0
+18 220927 2 0
+18 220927 3 0
+18 220927 4 0
+18 220927 5 0
+18 216291 1 4
+18 216291 2 4
+18 216291 3 4
+18 216291 4 4
+18 216291 5 4
+18 131478 1 9
+18 131478 2 9
+18 131478 3 9
+18 131478 4 9
+18 131478 5 9
+18 34594 1 13
+18 34594 2 13
+18 34594 3 13
+18 34594 4 13
+18 34594 5 13
+18 199406 1 10
+18 199406 2 10
+18 199406 3 10
+18 199406 4 10
+18 199406 5 10
+18 26816 1 6
+18 26816 2 6
+18 26816 3 6
+18 26816 4 6
+18 26816 5 6
+18 12041 1 8
+18 12041 2 8
+18 12041 3 8
+18 12041 4 8
+18 12041 5 8
+18 91593 1 5
+18 91593 2 5
+18 91593 3 5
+18 91593 4 5
+18 91593 5 5
+18 194186 1 3
+18 194186 2 3
+18 194186 3 3
+18 194186 4 3
+18 194186 5 3
+18 150343 1 2
+18 150343 2 2
+18 150343 3 2
+18 150343 4 2
+18 150343 5 2
+18 222016 1 6
+18 222016 2 6
+18 222016 3 6
+18 222016 4 6
+18 222016 5 6
+18 100345 1 3
+18 100345 2 3
+18 100345 3 3
+18 100345 4 3
+18 100345 5 3
+18 248323 1 17
+18 248323 2 17
+18 248323 3 17
+18 248323 4 17
+18 248323 5 17
+18 248898 1 13
+18 248898 2 13
+18 248898 3 13
+18 248898 4 13
+18 248898 5 13
+18 259523 1 9
+18 259523 2 9
+18 259523 3 9
+18 259523 4 9
+18 259523 5 9
+18 13668 1 12
+18 13668 2 12
+18 13668 3 12
+18 13668 4 12
+18 13668 5 12
+18 190429 1 3
+18 190429 2 3
+18 190429 3 3
+18 190429 4 3
+18 190429 5 3
+18 227309 1 9
+18 227309 2 9
+18 227309 3 9
+18 227309 4 9
+18 227309 5 9
+18 248240 1 10
+18 248240 2 10
+18 248240 3 10
+18 248240 4 10
+18 248240 5 10
+18 179569 1 5
+18 179569 2 5
+18 179569 3 5
+18 179569 4 5
+18 179569 5 5
+18 254832 1 4
+18 254832 2 4
+18 254832 3 4
+18 254832 4 4
+18 254832 5 4
+18 141688 1 9
+18 141688 2 9
+18 141688 3 9
+18 141688 4 9
+18 141688 5 9
+18 44089 1 17
+18 44089 2 17
+18 44089 3 17
+18 44089 4 17
+18 44089 5 17
+18 145850 1 15
+18 145850 2 15
+18 145850 3 15
+18 145850 4 15
+18 145850 5 15
+18 149351 1 1
+18 149351 2 1
+18 149351 3 1
+18 149351 4 1
+18 149351 5 1
+18 161161 1 17
+18 161161 2 17
+18 161161 3 17
+18 161161 4 17
+18 161161 5 17
+18 804 1 10
+18 804 2 10
+18 804 3 10
+18 804 4 10
+18 804 5 10
+18 204942 1 0
+18 204942 2 0
+18 204942 3 0
+18 204942 4 0
+18 204942 5 0
+18 109633 1 10
+18 109633 2 10
+18 109633 3 10
+18 109633 4 10
+18 109633 5 10
+18 189623 1 1
+18 189623 2 1
+18 189623 3 1
+18 189623 4 1
+18 189623 5 1
+18 117578 1 15
+18 117578 2 15
+18 117578 3 15
+18 117578 4 15
+18 117578 5 15
+18 42863 1 13
+18 42863 2 13
+18 42863 3 13
+18 42863 4 13
+18 42863 5 13
+18 138963 1 14
+18 138963 2 14
+18 138963 3 14
+18 138963 4 14
+18 138963 5 14
+18 65040 1 1
+18 65040 2 1
+18 65040 3 1
+18 65040 4 1
+18 65040 5 1
+18 59160 1 4
+18 59160 2 4
+18 59160 3 4
+18 59160 4 4
+18 59160 5 4
+18 128405 1 5
+18 128405 2 5
+18 128405 3 5
+18 128405 4 5
+18 128405 5 5
+18 186053 1 12
+18 186053 2 12
+18 186053 3 12
+18 186053 4 12
+18 186053 5 12
+18 205204 1 2
+18 205204 2 2
+18 205204 3 2
+18 205204 4 2
+18 205204 5 2
+18 179473 1 4
+18 179473 2 4
+18 179473 3 4
+18 179473 4 4
+18 179473 5 4
+18 206442 1 2
+18 206442 2 2
+18 206442 3 2
+18 206442 4 2
+18 206442 5 2
+18 81168 1 5
+18 81168 2 5
+18 81168 3 5
+18 81168 4 5
+18 81168 5 5
+18 209591 1 3
+18 209591 2 3
+18 209591 3 3
+18 209591 4 3
+18 209591 5 3
+18 9801 1 15
+18 9801 2 15
+18 9801 3 15
+18 9801 4 15
+18 9801 5 15
+18 7180 1 17
+18 7180 2 17
+18 7180 3 17
+18 7180 4 17
+18 7180 5 17
+18 148102 1 7
+18 148102 2 7
+18 148102 3 7
+18 148102 4 7
+18 148102 5 7
+19 285360 1 12
+19 285360 2 12
+19 285360 3 12
+19 285360 4 12
+19 285360 5 12
+19 39966 1 6
+19 39966 2 6
+19 39966 3 6
+19 39966 4 6
+19 39966 5 6
+19 439938 1 15
+19 439938 2 15
+19 439938 3 15
+19 439938 4 15
+19 439938 5 15
+19 276172 1 1
+19 276172 2 1
+19 276172 3 1
+19 276172 4 1
+19 276172 5 1
+19 371729 1 17
+19 371729 2 17
+19 371729 3 17
+19 371729 4 17
+19 371729 5 17
+19 168977 1 4
+19 168977 2 4
+19 168977 3 4
+19 168977 4 4
+19 168977 5 4
+19 161548 1 14
+19 161548 2 14
+19 161548 3 14
+19 161548 4 14
+19 161548 5 14
+19 497098 1 15
+19 497098 2 15
+19 497098 3 15
+19 497098 4 15
+19 497098 5 15
+19 51980 1 4
+19 51980 2 4
+19 51980 3 4
+19 51980 4 4
+19 51980 5 4
+19 84417 1 10
+19 84417 2 10
+19 84417 3 10
+19 84417 4 10
+19 84417 5 10
+19 508848 1 3
+19 508848 2 3
+19 508848 3 3
+19 508848 4 3
+19 508848 5 3
+19 249975 1 10
+19 249975 2 10
+19 249975 3 10
+19 249975 4 10
+19 249975 5 10
+19 471817 1 0
+19 471817 2 0
+19 471817 3 0
+19 471817 4 0
+19 471817 5 0
+19 420898 1 14
+19 420898 2 14
+19 420898 3 14
+19 420898 4 14
+19 420898 5 14
+19 62009 1 6
+19 62009 2 6
+19 62009 3 6
+19 62009 4 6
+19 62009 5 6
+19 261112 1 3
+19 261112 2 3
+19 261112 3 3
+19 261112 4 3
+19 261112 5 3
+19 268374 1 7
+19 268374 2 7
+19 268374 3 7
+19 268374 4 7
+19 268374 5 7
+19 92078 1 15
+19 92078 2 15
+19 92078 3 15
+19 92078 4 15
+19 92078 5 15
+19 146323 1 13
+19 146323 2 13
+19 146323 3 13
+19 146323 4 13
+19 146323 5 13
+19 48955 1 10
+19 48955 2 10
+19 48955 3 10
+19 48955 4 10
+19 48955 5 10
+19 336033 1 0
+19 336033 2 0
+19 336033 3 0
+19 336033 4 0
+19 336033 5 0
+19 4833 1 2
+19 4833 2 2
+19 4833 3 2
+19 4833 4 2
+19 4833 5 2
+19 359506 1 3
+19 359506 2 3
+19 359506 3 3
+19 359506 4 3
+19 359506 5 3
+19 477037 1 7
+19 477037 2 7
+19 477037 3 7
+19 477037 4 7
+19 477037 5 7
+19 109440 1 0
+19 109440 2 0
+19 109440 3 0
+19 109440 4 0
+19 109440 5 0
+19 27324 1 0
+19 27324 2 0
+19 27324 3 0
+19 27324 4 0
+19 27324 5 0
+19 361772 1 15
+19 361772 2 15
+19 361772 3 15
+19 361772 4 15
+19 361772 5 15
+19 150657 1 1
+19 150657 2 1
+19 150657 3 1
+19 150657 4 1
+19 150657 5 1
+19 174825 1 8
+19 174825 2 8
+19 174825 3 8
+19 174825 4 8
+19 174825 5 8
+19 352070 1 12
+19 352070 2 12
+19 352070 3 12
+19 352070 4 12
+19 352070 5 12
+19 195450 1 13
+19 195450 2 13
+19 195450 3 13
+19 195450 4 13
+19 195450 5 13
+19 468400 1 2
+19 468400 2 2
+19 468400 3 2
+19 468400 4 2
+19 468400 5 2
+19 330682 1 10
+19 330682 2 10
+19 330682 3 10
+19 330682 4 10
+19 330682 5 10
+19 45062 1 3
+19 45062 2 3
+19 45062 3 3
+19 45062 4 3
+19 45062 5 3
+19 313788 1 1
+19 313788 2 1
+19 313788 3 1
+19 313788 4 1
+19 313788 5 1
+19 60915 1 2
+19 60915 2 2
+19 60915 3 2
+19 60915 4 2
+19 60915 5 2
+19 44594 1 17
+19 44594 2 17
+19 44594 3 17
+19 44594 4 17
+19 44594 5 17
+19 252043 1 17
+19 252043 2 17
+19 252043 3 17
+19 252043 4 17
+19 252043 5 17
+19 401426 1 17
+19 401426 2 17
+19 401426 3 17
+19 401426 4 17
+19 401426 5 17
+19 243851 1 17
+19 243851 2 17
+19 243851 3 17
+19 243851 4 17
+19 243851 5 17
+19 388726 1 4
+19 388726 2 4
+19 388726 3 4
+19 388726 4 4
+19 388726 5 4
+19 134372 1 14
+19 134372 2 14
+19 134372 3 14
+19 134372 4 14
+19 134372 5 14
+19 263363 1 17
+19 263363 2 17
+19 263363 3 17
+19 263363 4 17
+19 263363 5 17
+19 120186 1 15
+19 120186 2 15
+19 120186 3 15
+19 120186 4 15
+19 120186 5 15
+19 245005 1 6
+19 245005 2 6
+19 245005 3 6
+19 245005 4 6
+19 245005 5 6
+19 345640 1 4
+19 345640 2 4
+19 345640 3 4
+19 345640 4 4
+19 345640 5 4
+19 292026 1 1
+19 292026 2 1
+19 292026 3 1
+19 292026 4 1
+19 292026 5 1
+19 337415 1 14
+19 337415 2 14
+19 337415 3 14
+19 337415 4 14
+19 337415 5 14
+19 18276 1 2
+19 18276 2 2
+19 18276 3 2
+19 18276 4 2
+19 18276 5 2
+19 24304 1 7
+19 24304 2 7
+19 24304 3 7
+19 24304 4 7
+19 24304 5 7
+19 70660 1 1
+19 70660 2 1
+19 70660 3 1
+19 70660 4 1
+19 70660 5 1
+19 426302 1 13
+19 426302 2 13
+19 426302 3 13
+19 426302 4 13
+19 426302 5 13
+19 405580 1 15
+19 405580 2 15
+19 405580 3 15
+19 405580 4 15
+19 405580 5 15
+19 16344 1 6
+19 16344 2 6
+19 16344 3 6
+19 16344 4 6
+19 16344 5 6
+19 486995 1 7
+19 486995 2 7
+19 486995 3 7
+19 486995 4 7
+19 486995 5 7
+19 338030 1 3
+19 338030 2 3
+19 338030 3 3
+19 338030 4 3
+19 338030 5 3
+19 22647 1 17
+19 22647 2 17
+19 22647 3 17
+19 22647 4 17
+19 22647 5 17
+19 400385 1 13
+19 400385 2 13
+19 400385 3 13
+19 400385 4 13
+19 400385 5 13
+19 51070 1 8
+19 51070 2 8
+19 51070 3 8
+19 51070 4 8
+19 51070 5 8
+19 19369 1 14
+19 19369 2 14
+19 19369 3 14
+19 19369 4 14
+19 19369 5 14
+19 407294 1 17
+19 407294 2 17
+19 407294 3 17
+19 407294 4 17
+19 407294 5 17
+19 310674 1 1
+19 310674 2 1
+19 310674 3 1
+19 310674 4 1
+19 310674 5 1
+19 228351 1 6
+19 228351 2 6
+19 228351 3 6
+19 228351 4 6
+19 228351 5 6
+19 302663 1 7
+19 302663 2 7
+19 302663 3 7
+19 302663 4 7
+19 302663 5 7
+20 198355 1 15
+20 198355 2 15
+20 198355 3 15
+20 198355 4 15
+20 198355 5 15
+20 296878 1 2
+20 296878 2 2
+20 296878 3 2
+20 296878 4 2
+20 296878 5 2
+20 760518 1 8
+20 760518 2 8
+20 760518 3 8
+20 760518 4 8
+20 760518 5 8
+20 924592 1 1
+20 924592 2 1
+20 924592 3 1
+20 924592 4 1
+20 924592 5 1
+20 561909 1 14
+20 561909 2 14
+20 561909 3 14
+20 561909 4 14
+20 561909 5 14
+20 364293 1 9
+20 364293 2 9
+20 364293 3 9
+20 364293 4 9
+20 364293 5 9
+20 431304 1 15
+20 431304 2 15
+20 431304 3 15
+20 431304 4 15
+20 431304 5 15
+20 24977 1 2
+20 24977 2 2
+20 24977 3 2
+20 24977 4 2
+20 24977 5 2
+20 98684 1 12
+20 98684 2 12
+20 98684 3 12
+20 98684 4 12
+20 98684 5 12
+20 116875 1 6
+20 116875 2 6
+20 116875 3 6
+20 116875 4 6
+20 116875 5 6
+20 121330 1 14
+20 121330 2 14
+20 121330 3 14
+20 121330 4 14
+20 121330 5 14
+20 977011 1 7
+20 977011 2 7
+20 977011 3 7
+20 977011 4 7
+20 977011 5 7
+20 789443 1 2
+20 789443 2 2
+20 789443 3 2
+20 789443 4 2
+20 789443 5 2
+20 539203 1 5
+20 539203 2 5
+20 539203 3 5
+20 539203 4 5
+20 539203 5 5
+20 981911 1 15
+20 981911 2 15
+20 981911 3 15
+20 981911 4 15
+20 981911 5 15
+20 495588 1 1
+20 495588 2 1
+20 495588 3 1
+20 495588 4 1
+20 495588 5 1
+20 24759 1 2
+20 24759 2 2
+20 24759 3 2
+20 24759 4 2
+20 24759 5 2
+20 355299 1 13
+20 355299 2 13
+20 355299 3 13
+20 355299 4 13
+20 355299 5 13
+20 706015 1 0
+20 706015 2 0
+20 706015 3 0
+20 706015 4 0
+20 706015 5 0
+20 1024100 1 13
+20 1024100 2 13
+20 1024100 3 13
+20 1024100 4 13
+20 1024100 5 13
+20 672600 1 7
+20 672600 2 7
+20 672600 3 7
+20 672600 4 7
+20 672600 5 7
+20 420182 1 8
+20 420182 2 8
+20 420182 3 8
+20 420182 4 8
+20 420182 5 8
+20 149062 1 1
+20 149062 2 1
+20 149062 3 1
+20 149062 4 1
+20 149062 5 1
+20 292328 1 7
+20 292328 2 7
+20 292328 3 7
+20 292328 4 7
+20 292328 5 7
+20 522558 1 2
+20 522558 2 2
+20 522558 3 2
+20 522558 4 2
+20 522558 5 2
+20 628026 1 9
+20 628026 2 9
+20 628026 3 9
+20 628026 4 9
+20 628026 5 9
+20 139803 1 0
+20 139803 2 0
+20 139803 3 0
+20 139803 4 0
+20 139803 5 0
+20 457303 1 1
+20 457303 2 1
+20 457303 3 1
+20 457303 4 1
+20 457303 5 1
+20 559378 1 12
+20 559378 2 12
+20 559378 3 12
+20 559378 4 12
+20 559378 5 12
+20 478051 1 1
+20 478051 2 1
+20 478051 3 1
+20 478051 4 1
+20 478051 5 1
+20 670978 1 5
+20 670978 2 5
+20 670978 3 5
+20 670978 4 5
+20 670978 5 5
+20 782352 1 14
+20 782352 2 14
+20 782352 3 14
+20 782352 4 14
+20 782352 5 14
+20 215312 1 15
+20 215312 2 15
+20 215312 3 15
+20 215312 4 15
+20 215312 5 15
+20 807766 1 13
+20 807766 2 13
+20 807766 3 13
+20 807766 4 13
+20 807766 5 13
+20 1027955 1 17
+20 1027955 2 17
+20 1027955 3 17
+20 1027955 4 17
+20 1027955 5 17
+20 724067 1 1
+20 724067 2 1
+20 724067 3 1
+20 724067 4 1
+20 724067 5 1
+20 179596 1 3
+20 179596 2 3
+20 179596 3 3
+20 179596 4 3
+20 179596 5 3
+20 8911 1 13
+20 8911 2 13
+20 8911 3 13
+20 8911 4 13
+20 8911 5 13
+20 462137 1 1
+20 462137 2 1
+20 462137 3 1
+20 462137 4 1
+20 462137 5 1
+20 451091 1 2
+20 451091 2 2
+20 451091 3 2
+20 451091 4 2
+20 451091 5 2
+20 837481 1 4
+20 837481 2 4
+20 837481 3 4
+20 837481 4 4
+20 837481 5 4
+20 61499 1 12
+20 61499 2 12
+20 61499 3 12
+20 61499 4 12
+20 61499 5 12
+20 64499 1 1
+20 64499 2 1
+20 64499 3 1
+20 64499 4 1
+20 64499 5 1
+20 498651 1 14
+20 498651 2 14
+20 498651 3 14
+20 498651 4 14
+20 498651 5 14
+20 139939 1 7
+20 139939 2 7
+20 139939 3 7
+20 139939 4 7
+20 139939 5 7
+20 1021247 1 13
+20 1021247 2 13
+20 1021247 3 13
+20 1021247 4 13
+20 1021247 5 13
+20 203158 1 4
+20 203158 2 4
+20 203158 3 4
+20 203158 4 4
+20 203158 5 4
+20 165605 1 5
+20 165605 2 5
+20 165605 3 5
+20 165605 4 5
+20 165605 5 5
+20 996551 1 10
+20 996551 2 10
+20 996551 3 10
+20 996551 4 10
+20 996551 5 10
+20 344367 1 1
+20 344367 2 1
+20 344367 3 1
+20 344367 4 1
+20 344367 5 1
+20 471785 1 7
+20 471785 2 7
+20 471785 3 7
+20 471785 4 7
+20 471785 5 7
+20 552276 1 8
+20 552276 2 8
+20 552276 3 8
+20 552276 4 8
+20 552276 5 8
+20 535414 1 7
+20 535414 2 7
+20 535414 3 7
+20 535414 4 7
+20 535414 5 7
+20 850839 1 17
+20 850839 2 17
+20 850839 3 17
+20 850839 4 17
+20 850839 5 17
+20 707079 1 2
+20 707079 2 2
+20 707079 3 2
+20 707079 4 2
+20 707079 5 2
+20 311484 1 2
+20 311484 2 2
+20 311484 3 2
+20 311484 4 2
+20 311484 5 2
+20 682726 1 15
+20 682726 2 15
+20 682726 3 15
+20 682726 4 15
+20 682726 5 15
+20 718518 1 7
+20 718518 2 7
+20 718518 3 7
+20 718518 4 7
+20 718518 5 7
+20 584929 1 15
+20 584929 2 15
+20 584929 3 15
+20 584929 4 15
+20 584929 5 15
+20 496804 1 12
+20 496804 2 12
+20 496804 3 12
+20 496804 4 12
+20 496804 5 12
+20 871520 1 3
+20 871520 2 3
+20 871520 3 3
+20 871520 4 3
+20 871520 5 3
+20 766462 1 3
+20 766462 2 3
+20 766462 3 3
+20 766462 4 3
+20 766462 5 3
+20 547770 1 10
+20 547770 2 10
+20 547770 3 10
+20 547770 4 10
+20 547770 5 10
+20 289035 1 17
+20 289035 2 17
+20 289035 3 17
+20 289035 4 17
+20 289035 5 17
+21 1544102 1 17
+21 1544102 2 17
+21 1544102 3 17
+21 1544102 4 17
+21 1544102 5 17
+21 1921124 1 4
+21 1921124 2 4
+21 1921124 3 4
+21 1921124 4 4
+21 1921124 5 4
+21 1244065 1 6
+21 1244065 2 6
+21 1244065 3 6
+21 1244065 4 6
+21 1244065 5 6
+21 949419 1 15
+21 949419 2 15
+21 949419 3 15
+21 949419 4 15
+21 949419 5 15
+21 809660 1 5
+21 809660 2 5
+21 809660 3 5
+21 809660 4 5
+21 809660 5 5
+21 2081078 1 10
+21 2081078 2 10
+21 2081078 3 10
+21 2081078 4 10
+21 2081078 5 10
+21 1324116 1 15
+21 1324116 2 15
+21 1324116 3 15
+21 1324116 4 15
+21 1324116 5 15
+21 769413 1 8
+21 769413 2 8
+21 769413 3 8
+21 769413 4 8
+21 769413 5 8
+21 1471174 1 1
+21 1471174 2 1
+21 1471174 3 1
+21 1471174 4 1
+21 1471174 5 1
+21 2010804 1 7
+21 2010804 2 7
+21 2010804 3 7
+21 2010804 4 7
+21 2010804 5 7
+21 1616690 1 14
+21 1616690 2 14
+21 1616690 3 14
+21 1616690 4 14
+21 1616690 5 14
+21 1017561 1 9
+21 1017561 2 9
+21 1017561 3 9
+21 1017561 4 9
+21 1017561 5 9
+21 957826 1 0
+21 957826 2 0
+21 957826 3 0
+21 957826 4 0
+21 957826 5 0
+21 562864 1 6
+21 562864 2 6
+21 562864 3 6
+21 562864 4 6
+21 562864 5 6
+21 536746 1 4
+21 536746 2 4
+21 536746 3 4
+21 536746 4 4
+21 536746 5 4
+21 2010490 1 17
+21 2010490 2 17
+21 2010490 3 17
+21 2010490 4 17
+21 2010490 5 17
+21 814896 1 6
+21 814896 2 6
+21 814896 3 6
+21 814896 4 6
+21 814896 5 6
+21 2085665 1 5
+21 2085665 2 5
+21 2085665 3 5
+21 2085665 4 5
+21 2085665 5 5
+21 608239 1 12
+21 608239 2 12
+21 608239 3 12
+21 608239 4 12
+21 608239 5 12
+21 1114271 1 6
+21 1114271 2 6
+21 1114271 3 6
+21 1114271 4 6
+21 1114271 5 6
+21 1578775 1 5
+21 1578775 2 5
+21 1578775 3 5
+21 1578775 4 5
+21 1578775 5 5
+21 293537 1 2
+21 293537 2 2
+21 293537 3 2
+21 293537 4 2
+21 293537 5 2
+21 1260407 1 8
+21 1260407 2 8
+21 1260407 3 8
+21 1260407 4 8
+21 1260407 5 8
+21 569959 1 4
+21 569959 2 4
+21 569959 3 4
+21 569959 4 4
+21 569959 5 4
+21 1653758 1 9
+21 1653758 2 9
+21 1653758 3 9
+21 1653758 4 9
+21 1653758 5 9
+21 643309 1 0
+21 643309 2 0
+21 643309 3 0
+21 643309 4 0
+21 643309 5 0
+21 1982846 1 3
+21 1982846 2 3
+21 1982846 3 3
+21 1982846 4 3
+21 1982846 5 3
+21 1986639 1 17
+21 1986639 2 17
+21 1986639 3 17
+21 1986639 4 17
+21 1986639 5 17
+21 1370291 1 17
+21 1370291 2 17
+21 1370291 3 17
+21 1370291 4 17
+21 1370291 5 17
+21 1656681 1 8
+21 1656681 2 8
+21 1656681 3 8
+21 1656681 4 8
+21 1656681 5 8
+21 241796 1 4
+21 241796 2 4
+21 241796 3 4
+21 241796 4 4
+21 241796 5 4
+21 215997 1 6
+21 215997 2 6
+21 215997 3 6
+21 215997 4 6
+21 215997 5 6
+21 821384 1 17
+21 821384 2 17
+21 821384 3 17
+21 821384 4 17
+21 821384 5 17
+21 331161 1 1
+21 331161 2 1
+21 331161 3 1
+21 331161 4 1
+21 331161 5 1
+21 17355 1 5
+21 17355 2 5
+21 17355 3 5
+21 17355 4 5
+21 17355 5 5
+21 1905273 1 7
+21 1905273 2 7
+21 1905273 3 7
+21 1905273 4 7
+21 1905273 5 7
+21 1045457 1 10
+21 1045457 2 10
+21 1045457 3 10
+21 1045457 4 10
+21 1045457 5 10
+21 799145 1 9
+21 799145 2 9
+21 799145 3 9
+21 799145 4 9
+21 799145 5 9
+21 683994 1 13
+21 683994 2 13
+21 683994 3 13
+21 683994 4 13
+21 683994 5 13
+21 1750830 1 4
+21 1750830 2 4
+21 1750830 3 4
+21 1750830 4 4
+21 1750830 5 4
+21 1346663 1 13
+21 1346663 2 13
+21 1346663 3 13
+21 1346663 4 13
+21 1346663 5 13
+21 1200358 1 6
+21 1200358 2 6
+21 1200358 3 6
+21 1200358 4 6
+21 1200358 5 6
+21 968444 1 4
+21 968444 2 4
+21 968444 3 4
+21 968444 4 4
+21 968444 5 4
+21 469486 1 15
+21 469486 2 15
+21 469486 3 15
+21 469486 4 15
+21 469486 5 15
+21 223784 1 3
+21 223784 2 3
+21 223784 3 3
+21 223784 4 3
+21 223784 5 3
+21 841795 1 4
+21 841795 2 4
+21 841795 3 4
+21 841795 4 4
+21 841795 5 4
+21 290242 1 2
+21 290242 2 2
+21 290242 3 2
+21 290242 4 2
+21 290242 5 2
+21 1704107 1 2
+21 1704107 2 2
+21 1704107 3 2
+21 1704107 4 2
+21 1704107 5 2
+21 1087348 1 9
+21 1087348 2 9
+21 1087348 3 9
+21 1087348 4 9
+21 1087348 5 9
+21 513237 1 2
+21 513237 2 2
+21 513237 3 2
+21 513237 4 2
+21 513237 5 2
+21 761725 1 13
+21 761725 2 13
+21 761725 3 13
+21 761725 4 13
+21 761725 5 13
+21 577471 1 6
+21 577471 2 6
+21 577471 3 6
+21 577471 4 6
+21 577471 5 6
+21 875954 1 9
+21 875954 2 9
+21 875954 3 9
+21 875954 4 9
+21 875954 5 9
+21 283735 1 8
+21 283735 2 8
+21 283735 3 8
+21 283735 4 8
+21 283735 5 8
+21 541381 1 17
+21 541381 2 17
+21 541381 3 17
+21 541381 4 17
+21 541381 5 17
+21 1774181 1 14
+21 1774181 2 14
+21 1774181 3 14
+21 1774181 4 14
+21 1774181 5 14
+21 500169 1 17
+21 500169 2 17
+21 500169 3 17
+21 500169 4 17
+21 500169 5 17
+21 1201575 1 7
+21 1201575 2 7
+21 1201575 3 7
+21 1201575 4 7
+21 1201575 5 7
+21 691701 1 1
+21 691701 2 1
+21 691701 3 1
+21 691701 4 1
+21 691701 5 1
+21 172861 1 4
+21 172861 2 4
+21 172861 3 4
+21 172861 4 4
+21 172861 5 4
+21 544935 1 0
+21 544935 2 0
+21 544935 3 0
+21 544935 4 0
+21 544935 5 0
+21 543047 1 3
+21 543047 2 3
+21 543047 3 3
+21 543047 4 3
+21 543047 5 3
+21 1555372 1 3
+21 1555372 2 3
+21 1555372 3 3
+21 1555372 4 3
+21 1555372 5 3
+21 1754316 1 8
+21 1754316 2 8
+21 1754316 3 8
+21 1754316 4 8
+21 1754316 5 8
+22 1701163 1 15
+22 1701163 2 15
+22 1701163 3 15
+22 1701163 4 15
+22 1701163 5 15
+22 2291265 1 9
+22 2291265 2 9
+22 2291265 3 9
+22 2291265 4 9
+22 2291265 5 9
+22 2939154 1 17
+22 2939154 2 17
+22 2939154 3 17
+22 2939154 4 17
+22 2939154 5 17
+22 874939 1 9
+22 874939 2 9
+22 874939 3 9
+22 874939 4 9
+22 874939 5 9
+22 66406 1 0
+22 66406 2 0
+22 66406 3 0
+22 66406 4 0
+22 66406 5 0
+22 2173604 1 10
+22 2173604 2 10
+22 2173604 3 10
+22 2173604 4 10
+22 2173604 5 10
+22 3888560 1 9
+22 3888560 2 9
+22 3888560 3 9
+22 3888560 4 9
+22 3888560 5 9
+22 633256 1 9
+22 633256 2 9
+22 633256 3 9
+22 633256 4 9
+22 633256 5 9
+22 499433 1 0
+22 499433 2 0
+22 499433 3 0
+22 499433 4 0
+22 499433 5 0
+22 523322 1 9
+22 523322 2 9
+22 523322 3 9
+22 523322 4 9
+22 523322 5 9
+22 3422065 1 9
+22 3422065 2 9
+22 3422065 3 9
+22 3422065 4 9
+22 3422065 5 9
+22 1944488 1 13
+22 1944488 2 13
+22 1944488 3 13
+22 1944488 4 13
+22 1944488 5 13
+22 1501254 1 6
+22 1501254 2 6
+22 1501254 3 6
+22 1501254 4 6
+22 1501254 5 6
+22 3637609 1 9
+22 3637609 2 9
+22 3637609 3 9
+22 3637609 4 9
+22 3637609 5 9
+22 3969393 1 3
+22 3969393 2 3
+22 3969393 3 3
+22 3969393 4 3
+22 3969393 5 3
+22 3757241 1 9
+22 3757241 2 9
+22 3757241 3 9
+22 3757241 4 9
+22 3757241 5 9
+22 541635 1 2
+22 541635 2 2
+22 541635 3 2
+22 541635 4 2
+22 541635 5 2
+22 40295 1 1
+22 40295 2 1
+22 40295 3 1
+22 40295 4 1
+22 40295 5 1
+22 4047297 1 0
+22 4047297 2 0
+22 4047297 3 0
+22 4047297 4 0
+22 4047297 5 0
+22 3989485 1 8
+22 3989485 2 8
+22 3989485 3 8
+22 3989485 4 8
+22 3989485 5 8
+22 4103132 1 10
+22 4103132 2 10
+22 4103132 3 10
+22 4103132 4 10
+22 4103132 5 10
+22 1722049 1 5
+22 1722049 2 5
+22 1722049 3 5
+22 1722049 4 5
+22 1722049 5 5
+22 23525 1 9
+22 23525 2 9
+22 23525 3 9
+22 23525 4 9
+22 23525 5 9
+22 2882794 1 13
+22 2882794 2 13
+22 2882794 3 13
+22 2882794 4 13
+22 2882794 5 13
+22 3503039 1 15
+22 3503039 2 15
+22 3503039 3 15
+22 3503039 4 15
+22 3503039 5 15
+22 597461 1 7
+22 597461 2 7
+22 597461 3 7
+22 597461 4 7
+22 597461 5 7
+22 648021 1 14
+22 648021 2 14
+22 648021 3 14
+22 648021 4 14
+22 648021 5 14
+22 2641512 1 2
+22 2641512 2 2
+22 2641512 3 2
+22 2641512 4 2
+22 2641512 5 2
+22 3131854 1 0
+22 3131854 2 0
+22 3131854 3 0
+22 3131854 4 0
+22 3131854 5 0
+22 3363671 1 9
+22 3363671 2 9
+22 3363671 3 9
+22 3363671 4 9
+22 3363671 5 9
+22 480767 1 0
+22 480767 2 0
+22 480767 3 0
+22 480767 4 0
+22 480767 5 0
+22 866487 1 8
+22 866487 2 8
+22 866487 3 8
+22 866487 4 8
+22 866487 5 8
+22 3197473 1 1
+22 3197473 2 1
+22 3197473 3 1
+22 3197473 4 1
+22 3197473 5 1
+22 1760976 1 2
+22 1760976 2 2
+22 1760976 3 2
+22 1760976 4 2
+22 1760976 5 2
+22 952003 1 4
+22 952003 2 4
+22 952003 3 4
+22 952003 4 4
+22 952003 5 4
+22 458806 1 17
+22 458806 2 17
+22 458806 3 17
+22 458806 4 17
+22 458806 5 17
+22 2642177 1 15
+22 2642177 2 15
+22 2642177 3 15
+22 2642177 4 15
+22 2642177 5 15
+22 3671322 1 10
+22 3671322 2 10
+22 3671322 3 10
+22 3671322 4 10
+22 3671322 5 10
+22 18422 1 12
+22 18422 2 12
+22 18422 3 12
+22 18422 4 12
+22 18422 5 12
+22 4143069 1 0
+22 4143069 2 0
+22 4143069 3 0
+22 4143069 4 0
+22 4143069 5 0
+22 4013422 1 13
+22 4013422 2 13
+22 4013422 3 13
+22 4013422 4 13
+22 4013422 5 13
+22 3026661 1 13
+22 3026661 2 13
+22 3026661 3 13
+22 3026661 4 13
+22 3026661 5 13
+22 1402336 1 5
+22 1402336 2 5
+22 1402336 3 5
+22 1402336 4 5
+22 1402336 5 5
+22 3702708 1 10
+22 3702708 2 10
+22 3702708 3 10
+22 3702708 4 10
+22 3702708 5 10
+22 2069402 1 8
+22 2069402 2 8
+22 2069402 3 8
+22 2069402 4 8
+22 2069402 5 8
+22 1380150 1 15
+22 1380150 2 15
+22 1380150 3 15
+22 1380150 4 15
+22 1380150 5 15
+22 2126142 1 12
+22 2126142 2 12
+22 2126142 3 12
+22 2126142 4 12
+22 2126142 5 12
+22 3380057 1 0
+22 3380057 2 0
+22 3380057 3 0
+22 3380057 4 0
+22 3380057 5 0
+22 814956 1 9
+22 814956 2 9
+22 814956 3 9
+22 814956 4 9
+22 814956 5 9
+22 1055203 1 1
+22 1055203 2 1
+22 1055203 3 1
+22 1055203 4 1
+22 1055203 5 1
+22 940480 1 12
+22 940480 2 12
+22 940480 3 12
+22 940480 4 12
+22 940480 5 12
+22 3647615 1 17
+22 3647615 2 17
+22 3647615 3 17
+22 3647615 4 17
+22 3647615 5 17
+22 3000063 1 6
+22 3000063 2 6
+22 3000063 3 6
+22 3000063 4 6
+22 3000063 5 6
+22 3033624 1 13
+22 3033624 2 13
+22 3033624 3 13
+22 3033624 4 13
+22 3033624 5 13
+22 3135628 1 9
+22 3135628 2 9
+22 3135628 3 9
+22 3135628 4 9
+22 3135628 5 9
+22 1580393 1 1
+22 1580393 2 1
+22 1580393 3 1
+22 1580393 4 1
+22 1580393 5 1
+22 4193568 1 8
+22 4193568 2 8
+22 4193568 3 8
+22 4193568 4 8
+22 4193568 5 8
+22 800980 1 10
+22 800980 2 10
+22 800980 3 10
+22 800980 4 10
+22 800980 5 10
+22 1419961 1 17
+22 1419961 2 17
+22 1419961 3 17
+22 1419961 4 17
+22 1419961 5 17
+22 1144691 1 3
+22 1144691 2 3
+22 1144691 3 3
+22 1144691 4 3
+22 1144691 5 3
+22 2573267 1 8
+22 2573267 2 8
+22 2573267 3 8
+22 2573267 4 8
+22 2573267 5 8
+22 3310445 1 7
+22 3310445 2 7
+22 3310445 3 7
+22 3310445 4 7
+22 3310445 5 7
+22 629717 1 13
+22 629717 2 13
+22 629717 3 13
+22 629717 4 13
+22 629717 5 13
+22 1552778 1 17
+22 1552778 2 17
+22 1552778 3 17
+22 1552778 4 17
+22 1552778 5 17
+23 3046911 1 1
+23 3046911 2 1
+23 3046911 3 1
+23 3046911 4 1
+23 3046911 5 1
+23 769783 1 9
+23 769783 2 9
+23 769783 3 9
+23 769783 4 9
+23 769783 5 9
+23 2374124 1 13
+23 2374124 2 13
+23 2374124 3 13
+23 2374124 4 13
+23 2374124 5 13
+23 2996918 1 15
+23 2996918 2 15
+23 2996918 3 15
+23 2996918 4 15
+23 2996918 5 15
+23 2411310 1 6
+23 2411310 2 6
+23 2411310 3 6
+23 2411310 4 6
+23 2411310 5 6
+23 744660 1 8
+23 744660 2 8
+23 744660 3 8
+23 744660 4 8
+23 744660 5 8
+23 7927100 1 17
+23 7927100 2 17
+23 7927100 3 17
+23 7927100 4 17
+23 7927100 5 17
+23 1377692 1 0
+23 1377692 2 0
+23 1377692 3 0
+23 1377692 4 0
+23 1377692 5 0
+23 2920499 1 4
+23 2920499 2 4
+23 2920499 3 4
+23 2920499 4 4
+23 2920499 5 4
+23 6611555 1 4
+23 6611555 2 4
+23 6611555 3 4
+23 6611555 4 4
+23 6611555 5 4
+23 723122 1 0
+23 723122 2 0
+23 723122 3 0
+23 723122 4 0
+23 723122 5 0
+23 5130765 1 14
+23 5130765 2 14
+23 5130765 3 14
+23 5130765 4 14
+23 5130765 5 14
+23 621060 1 6
+23 621060 2 6
+23 621060 3 6
+23 621060 4 6
+23 621060 5 6
+23 6806998 1 1
+23 6806998 2 1
+23 6806998 3 1
+23 6806998 4 1
+23 6806998 5 1
+23 3524228 1 7
+23 3524228 2 7
+23 3524228 3 7
+23 3524228 4 7
+23 3524228 5 7
+23 1077839 1 1
+23 1077839 2 1
+23 1077839 3 1
+23 1077839 4 1
+23 1077839 5 1
+23 5526077 1 8
+23 5526077 2 8
+23 5526077 3 8
+23 5526077 4 8
+23 5526077 5 8
+23 7013541 1 13
+23 7013541 2 13
+23 7013541 3 13
+23 7013541 4 13
+23 7013541 5 13
+23 4998096 1 9
+23 4998096 2 9
+23 4998096 3 9
+23 4998096 4 9
+23 4998096 5 9
+23 5128233 1 5
+23 5128233 2 5
+23 5128233 3 5
+23 5128233 4 5
+23 5128233 5 5
+23 1863578 1 9
+23 1863578 2 9
+23 1863578 3 9
+23 1863578 4 9
+23 1863578 5 9
+23 6838283 1 17
+23 6838283 2 17
+23 6838283 3 17
+23 6838283 4 17
+23 6838283 5 17
+23 1134869 1 1
+23 1134869 2 1
+23 1134869 3 1
+23 1134869 4 1
+23 1134869 5 1
+23 2111849 1 12
+23 2111849 2 12
+23 2111849 3 12
+23 2111849 4 12
+23 2111849 5 12
+23 1488511 1 9
+23 1488511 2 9
+23 1488511 3 9
+23 1488511 4 9
+23 1488511 5 9
+23 4807048 1 10
+23 4807048 2 10
+23 4807048 3 10
+23 4807048 4 10
+23 4807048 5 10
+23 393912 1 13
+23 393912 2 13
+23 393912 3 13
+23 393912 4 13
+23 393912 5 13
+23 5219424 1 0
+23 5219424 2 0
+23 5219424 3 0
+23 5219424 4 0
+23 5219424 5 0
+23 8137072 1 2
+23 8137072 2 2
+23 8137072 3 2
+23 8137072 4 2
+23 8137072 5 2
+23 5590877 1 1
+23 5590877 2 1
+23 5590877 3 1
+23 5590877 4 1
+23 5590877 5 1
+23 5294465 1 2
+23 5294465 2 2
+23 5294465 3 2
+23 5294465 4 2
+23 5294465 5 2
+23 1348707 1 6
+23 1348707 2 6
+23 1348707 3 6
+23 1348707 4 6
+23 1348707 5 6
+23 7997848 1 6
+23 7997848 2 6
+23 7997848 3 6
+23 7997848 4 6
+23 7997848 5 6
+23 7575827 1 10
+23 7575827 2 10
+23 7575827 3 10
+23 7575827 4 10
+23 7575827 5 10
+23 4135707 1 5
+23 4135707 2 5
+23 4135707 3 5
+23 4135707 4 5
+23 4135707 5 5
+23 5834316 1 0
+23 5834316 2 0
+23 5834316 3 0
+23 5834316 4 0
+23 5834316 5 0
+23 5605190 1 2
+23 5605190 2 2
+23 5605190 3 2
+23 5605190 4 2
+23 5605190 5 2
+23 3412980 1 4
+23 3412980 2 4
+23 3412980 3 4
+23 3412980 4 4
+23 3412980 5 4
+23 2337431 1 10
+23 2337431 2 10
+23 2337431 3 10
+23 2337431 4 10
+23 2337431 5 10
+23 1248504 1 17
+23 1248504 2 17
+23 1248504 3 17
+23 1248504 4 17
+23 1248504 5 17
+23 2425452 1 14
+23 2425452 2 14
+23 2425452 3 14
+23 2425452 4 14
+23 2425452 5 14
+23 5214096 1 6
+23 5214096 2 6
+23 5214096 3 6
+23 5214096 4 6
+23 5214096 5 6
+23 1257705 1 8
+23 1257705 2 8
+23 1257705 3 8
+23 1257705 4 8
+23 1257705 5 8
+23 527815 1 12
+23 527815 2 12
+23 527815 3 12
+23 527815 4 12
+23 527815 5 12
+23 4250399 1 5
+23 4250399 2 5
+23 4250399 3 5
+23 4250399 4 5
+23 4250399 5 5
+23 1200698 1 4
+23 1200698 2 4
+23 1200698 3 4
+23 1200698 4 4
+23 1200698 5 4
+23 4310378 1 8
+23 4310378 2 8
+23 4310378 3 8
+23 4310378 4 8
+23 4310378 5 8
+23 724255 1 6
+23 724255 2 6
+23 724255 3 6
+23 724255 4 6
+23 724255 5 6
+23 5100058 1 9
+23 5100058 2 9
+23 5100058 3 9
+23 5100058 4 9
+23 5100058 5 9
+23 6466953 1 4
+23 6466953 2 4
+23 6466953 3 4
+23 6466953 4 4
+23 6466953 5 4
+23 181844 1 17
+23 181844 2 17
+23 181844 3 17
+23 181844 4 17
+23 181844 5 17
+23 527081 1 15
+23 527081 2 15
+23 527081 3 15
+23 527081 4 15
+23 527081 5 15
+23 194874 1 0
+23 194874 2 0
+23 194874 3 0
+23 194874 4 0
+23 194874 5 0
+23 5612248 1 7
+23 5612248 2 7
+23 5612248 3 7
+23 5612248 4 7
+23 5612248 5 7
+23 2969929 1 15
+23 2969929 2 15
+23 2969929 3 15
+23 2969929 4 15
+23 2969929 5 15
+23 7237394 1 15
+23 7237394 2 15
+23 7237394 3 15
+23 7237394 4 15
+23 7237394 5 15
+23 865283 1 7
+23 865283 2 7
+23 865283 3 7
+23 865283 4 7
+23 865283 5 7
+23 235461 1 3
+23 235461 2 3
+23 235461 3 3
+23 235461 4 3
+23 235461 5 3
+23 6769613 1 0
+23 6769613 2 0
+23 6769613 3 0
+23 6769613 4 0
+23 6769613 5 0
+23 5015052 1 7
+23 5015052 2 7
+23 5015052 3 7
+23 5015052 4 7
+23 5015052 5 7
+23 3295257 1 13
+23 3295257 2 13
+23 3295257 3 13
+23 3295257 4 13
+23 3295257 5 13
+23 989877 1 1
+23 989877 2 1
+23 989877 3 1
+23 989877 4 1
+23 989877 5 1
+23 1637319 1 13
+23 1637319 2 13
+23 1637319 3 13
+23 1637319 4 13
+23 1637319 5 13
+23 3018058 1 13
+23 3018058 2 13
+23 3018058 3 13
+23 3018058 4 13
+23 3018058 5 13
+24 9775649 1 12
+24 9775649 2 12
+24 9775649 3 12
+24 9775649 4 12
+24 9775649 5 12
+24 14133895 1 9
+24 14133895 2 9
+24 14133895 3 9
+24 14133895 4 9
+24 14133895 5 9
+24 3743280 1 17
+24 3743280 2 17
+24 3743280 3 17
+24 3743280 4 17
+24 3743280 5 17
+24 1023898 1 3
+24 1023898 2 3
+24 1023898 3 3
+24 1023898 4 3
+24 1023898 5 3
+24 9941521 1 3
+24 9941521 2 3
+24 9941521 3 3
+24 9941521 4 3
+24 9941521 5 3
+24 10377160 1 3
+24 10377160 2 3
+24 10377160 3 3
+24 10377160 4 3
+24 10377160 5 3
+24 11342584 1 1
+24 11342584 2 1
+24 11342584 3 1
+24 11342584 4 1
+24 11342584 5 1
+24 9294179 1 1
+24 9294179 2 1
+24 9294179 3 1
+24 9294179 4 1
+24 9294179 5 1
+24 15025827 1 9
+24 15025827 2 9
+24 15025827 3 9
+24 15025827 4 9
+24 15025827 5 9
+24 3498285 1 14
+24 3498285 2 14
+24 3498285 3 14
+24 3498285 4 14
+24 3498285 5 14
+24 8199923 1 13
+24 8199923 2 13
+24 8199923 3 13
+24 8199923 4 13
+24 8199923 5 13
+24 90634 1 1
+24 90634 2 1
+24 90634 3 1
+24 90634 4 1
+24 90634 5 1
+24 12997310 1 6
+24 12997310 2 6
+24 12997310 3 6
+24 12997310 4 6
+24 12997310 5 6
+24 14265335 1 17
+24 14265335 2 17
+24 14265335 3 17
+24 14265335 4 17
+24 14265335 5 17
+24 5492707 1 13
+24 5492707 2 13
+24 5492707 3 13
+24 5492707 4 13
+24 5492707 5 13
+24 263738 1 13
+24 263738 2 13
+24 263738 3 13
+24 263738 4 13
+24 263738 5 13
+24 13671070 1 4
+24 13671070 2 4
+24 13671070 3 4
+24 13671070 4 4
+24 13671070 5 4
+24 8325339 1 0
+24 8325339 2 0
+24 8325339 3 0
+24 8325339 4 0
+24 8325339 5 0
+24 9752092 1 8
+24 9752092 2 8
+24 9752092 3 8
+24 9752092 4 8
+24 9752092 5 8
+24 10821970 1 5
+24 10821970 2 5
+24 10821970 3 5
+24 10821970 4 5
+24 10821970 5 5
+24 3248722 1 0
+24 3248722 2 0
+24 3248722 3 0
+24 3248722 4 0
+24 3248722 5 0
+24 11447937 1 12
+24 11447937 2 12
+24 11447937 3 12
+24 11447937 4 12
+24 11447937 5 12
+24 6691593 1 6
+24 6691593 2 6
+24 6691593 3 6
+24 6691593 4 6
+24 6691593 5 6
+24 10840036 1 7
+24 10840036 2 7
+24 10840036 3 7
+24 10840036 4 7
+24 10840036 5 7
+24 8193085 1 3
+24 8193085 2 3
+24 8193085 3 3
+24 8193085 4 3
+24 8193085 5 3
+24 13272070 1 17
+24 13272070 2 17
+24 13272070 3 17
+24 13272070 4 17
+24 13272070 5 17
+24 3317672 1 8
+24 3317672 2 8
+24 3317672 3 8
+24 3317672 4 8
+24 3317672 5 8
+24 9720374 1 6
+24 9720374 2 6
+24 9720374 3 6
+24 9720374 4 6
+24 9720374 5 6
+24 3803032 1 15
+24 3803032 2 15
+24 3803032 3 15
+24 3803032 4 15
+24 3803032 5 15
+24 8338298 1 12
+24 8338298 2 12
+24 8338298 3 12
+24 8338298 4 12
+24 8338298 5 12
+24 8391433 1 8
+24 8391433 2 8
+24 8391433 3 8
+24 8391433 4 8
+24 8391433 5 8
+24 3759812 1 17
+24 3759812 2 17
+24 3759812 3 17
+24 3759812 4 17
+24 3759812 5 17
+24 11028207 1 17
+24 11028207 2 17
+24 11028207 3 17
+24 11028207 4 17
+24 11028207 5 17
+24 7289955 1 15
+24 7289955 2 15
+24 7289955 3 15
+24 7289955 4 15
+24 7289955 5 15
+24 3277010 1 9
+24 3277010 2 9
+24 3277010 3 9
+24 3277010 4 9
+24 3277010 5 9
+24 15934652 1 4
+24 15934652 2 4
+24 15934652 3 4
+24 15934652 4 4
+24 15934652 5 4
+24 7837344 1 0
+24 7837344 2 0
+24 7837344 3 0
+24 7837344 4 0
+24 7837344 5 0
+24 6315577 1 15
+24 6315577 2 15
+24 6315577 3 15
+24 6315577 4 15
+24 6315577 5 15
+24 9738174 1 10
+24 9738174 2 10
+24 9738174 3 10
+24 9738174 4 10
+24 9738174 5 10
+24 16135808 1 4
+24 16135808 2 4
+24 16135808 3 4
+24 16135808 4 4
+24 16135808 5 4
+24 7068511 1 10
+24 7068511 2 10
+24 7068511 3 10
+24 7068511 4 10
+24 7068511 5 10
+24 7762664 1 5
+24 7762664 2 5
+24 7762664 3 5
+24 7762664 4 5
+24 7762664 5 5
+24 13117465 1 10
+24 13117465 2 10
+24 13117465 3 10
+24 13117465 4 10
+24 13117465 5 10
+24 9819176 1 9
+24 9819176 2 9
+24 9819176 3 9
+24 9819176 4 9
+24 9819176 5 9
+24 2572469 1 1
+24 2572469 2 1
+24 2572469 3 1
+24 2572469 4 1
+24 2572469 5 1
+24 4497745 1 1
+24 4497745 2 1
+24 4497745 3 1
+24 4497745 4 1
+24 4497745 5 1
+24 6842950 1 0
+24 6842950 2 0
+24 6842950 3 0
+24 6842950 4 0
+24 6842950 5 0
+24 28157 1 14
+24 28157 2 14
+24 28157 3 14
+24 28157 4 14
+24 28157 5 14
+24 9748348 1 15
+24 9748348 2 15
+24 9748348 3 15
+24 9748348 4 15
+24 9748348 5 15
+24 12554184 1 8
+24 12554184 2 8
+24 12554184 3 8
+24 12554184 4 8
+24 12554184 5 8
+24 8971577 1 4
+24 8971577 2 4
+24 8971577 3 4
+24 8971577 4 4
+24 8971577 5 4
+24 1701631 1 9
+24 1701631 2 9
+24 1701631 3 9
+24 1701631 4 9
+24 1701631 5 9
+24 11334757 1 6
+24 11334757 2 6
+24 11334757 3 6
+24 11334757 4 6
+24 11334757 5 6
+24 5922455 1 10
+24 5922455 2 10
+24 5922455 3 10
+24 5922455 4 10
+24 5922455 5 10
+24 6335742 1 7
+24 6335742 2 7
+24 6335742 3 7
+24 6335742 4 7
+24 6335742 5 7
+24 6162272 1 6
+24 6162272 2 6
+24 6162272 3 6
+24 6162272 4 6
+24 6162272 5 6
+24 9389682 1 3
+24 9389682 2 3
+24 9389682 3 3
+24 9389682 4 3
+24 9389682 5 3
+24 14185082 1 9
+24 14185082 2 9
+24 14185082 3 9
+24 14185082 4 9
+24 14185082 5 9
+24 4157744 1 1
+24 4157744 2 1
+24 4157744 3 1
+24 4157744 4 1
+24 4157744 5 1
+24 15978247 1 6
+24 15978247 2 6
+24 15978247 3 6
+24 15978247 4 6
+24 15978247 5 6
+24 2710908 1 7
+24 2710908 2 7
+24 2710908 3 7
+24 2710908 4 7
+24 2710908 5 7
+24 10358562 1 5
+24 10358562 2 5
+24 10358562 3 5
+24 10358562 4 5
+24 10358562 5 5
+24 10869634 1 15
+24 10869634 2 15
+24 10869634 3 15
+24 10869634 4 15
+24 10869634 5 15
+24 6150158 1 17
+24 6150158 2 17
+24 6150158 3 17
+24 6150158 4 17
+24 6150158 5 17
+25 27898613 1 5
+25 27898613 2 5
+25 27898613 3 5
+25 27898613 4 5
+25 27898613 5 5
+25 29501 1 1
+25 29501 2 1
+25 29501 3 1
+25 29501 4 1
+25 29501 5 1
+25 15761162 1 8
+25 15761162 2 8
+25 15761162 3 8
+25 15761162 4 8
+25 15761162 5 8
+25 15728788 1 14
+25 15728788 2 14
+25 15728788 3 14
+25 15728788 4 14
+25 15728788 5 14
+25 33257945 1 14
+25 33257945 2 14
+25 33257945 3 14
+25 33257945 4 14
+25 33257945 5 14
+25 25725432 1 1
+25 25725432 2 1
+25 25725432 3 1
+25 25725432 4 1
+25 25725432 5 1
+25 32158340 1 4
+25 32158340 2 4
+25 32158340 3 4
+25 32158340 4 4
+25 32158340 5 4
+25 14232919 1 6
+25 14232919 2 6
+25 14232919 3 6
+25 14232919 4 6
+25 14232919 5 6
+25 25835501 1 6
+25 25835501 2 6
+25 25835501 3 6
+25 25835501 4 6
+25 25835501 5 6
+25 17975125 1 17
+25 17975125 2 17
+25 17975125 3 17
+25 17975125 4 17
+25 17975125 5 17
+25 1306676 1 9
+25 1306676 2 9
+25 1306676 3 9
+25 1306676 4 9
+25 1306676 5 9
+25 15859824 1 7
+25 15859824 2 7
+25 15859824 3 7
+25 15859824 4 7
+25 15859824 5 7
+25 28894333 1 4
+25 28894333 2 4
+25 28894333 3 4
+25 28894333 4 4
+25 28894333 5 4
+25 9046116 1 15
+25 9046116 2 15
+25 9046116 3 15
+25 9046116 4 15
+25 9046116 5 15
+25 26019062 1 13
+25 26019062 2 13
+25 26019062 3 13
+25 26019062 4 13
+25 26019062 5 13
+25 1778640 1 9
+25 1778640 2 9
+25 1778640 3 9
+25 1778640 4 9
+25 1778640 5 9
+25 10266904 1 1
+25 10266904 2 1
+25 10266904 3 1
+25 10266904 4 1
+25 10266904 5 1
+25 6909977 1 3
+25 6909977 2 3
+25 6909977 3 3
+25 6909977 4 3
+25 6909977 5 3
+25 10702892 1 2
+25 10702892 2 2
+25 10702892 3 2
+25 10702892 4 2
+25 10702892 5 2
+25 11960717 1 6
+25 11960717 2 6
+25 11960717 3 6
+25 11960717 4 6
+25 11960717 5 6
+25 5203472 1 1
+25 5203472 2 1
+25 5203472 3 1
+25 5203472 4 1
+25 5203472 5 1
+25 29147083 1 17
+25 29147083 2 17
+25 29147083 3 17
+25 29147083 4 17
+25 29147083 5 17
+25 24580154 1 6
+25 24580154 2 6
+25 24580154 3 6
+25 24580154 4 6
+25 24580154 5 6
+25 14263395 1 8
+25 14263395 2 8
+25 14263395 3 8
+25 14263395 4 8
+25 14263395 5 8
+25 22955773 1 7
+25 22955773 2 7
+25 22955773 3 7
+25 22955773 4 7
+25 22955773 5 7
+25 21675961 1 8
+25 21675961 2 8
+25 21675961 3 8
+25 21675961 4 8
+25 21675961 5 8
+25 7257867 1 8
+25 7257867 2 8
+25 7257867 3 8
+25 7257867 4 8
+25 7257867 5 8
+25 20686894 1 5
+25 20686894 2 5
+25 20686894 3 5
+25 20686894 4 5
+25 20686894 5 5
+25 29779770 1 0
+25 29779770 2 0
+25 29779770 3 0
+25 29779770 4 0
+25 29779770 5 0
+25 27342720 1 8
+25 27342720 2 8
+25 27342720 3 8
+25 27342720 4 8
+25 27342720 5 8
+25 622218 1 9
+25 622218 2 9
+25 622218 3 9
+25 622218 4 9
+25 622218 5 9
+25 12630641 1 8
+25 12630641 2 8
+25 12630641 3 8
+25 12630641 4 8
+25 12630641 5 8
+25 3245670 1 0
+25 3245670 2 0
+25 3245670 3 0
+25 3245670 4 0
+25 3245670 5 0
+25 521894 1 8
+25 521894 2 8
+25 521894 3 8
+25 521894 4 8
+25 521894 5 8
+25 14849322 1 2
+25 14849322 2 2
+25 14849322 3 2
+25 14849322 4 2
+25 14849322 5 2
+25 12921554 1 8
+25 12921554 2 8
+25 12921554 3 8
+25 12921554 4 8
+25 12921554 5 8
+25 23383269 1 3
+25 23383269 2 3
+25 23383269 3 3
+25 23383269 4 3
+25 23383269 5 3
+25 10251539 1 2
+25 10251539 2 2
+25 10251539 3 2
+25 10251539 4 2
+25 10251539 5 2
+25 16251487 1 14
+25 16251487 2 14
+25 16251487 3 14
+25 16251487 4 14
+25 16251487 5 14
+25 9046939 1 3
+25 9046939 2 3
+25 9046939 3 3
+25 9046939 4 3
+25 9046939 5 3
+25 1286237 1 10
+25 1286237 2 10
+25 1286237 3 10
+25 1286237 4 10
+25 1286237 5 10
+25 1561491 1 6
+25 1561491 2 6
+25 1561491 3 6
+25 1561491 4 6
+25 1561491 5 6
+25 25555747 1 2
+25 25555747 2 2
+25 25555747 3 2
+25 25555747 4 2
+25 25555747 5 2
+25 6644283 1 17
+25 6644283 2 17
+25 6644283 3 17
+25 6644283 4 17
+25 6644283 5 17
+25 25724985 1 6
+25 25724985 2 6
+25 25724985 3 6
+25 25724985 4 6
+25 25724985 5 6
+25 123989 1 14
+25 123989 2 14
+25 123989 3 14
+25 123989 4 14
+25 123989 5 14
+25 17415794 1 7
+25 17415794 2 7
+25 17415794 3 7
+25 17415794 4 7
+25 17415794 5 7
+25 26732483 1 12
+25 26732483 2 12
+25 26732483 3 12
+25 26732483 4 12
+25 26732483 5 12
+25 30810665 1 14
+25 30810665 2 14
+25 30810665 3 14
+25 30810665 4 14
+25 30810665 5 14
+25 5383023 1 6
+25 5383023 2 6
+25 5383023 3 6
+25 5383023 4 6
+25 5383023 5 6
+25 20795854 1 1
+25 20795854 2 1
+25 20795854 3 1
+25 20795854 4 1
+25 20795854 5 1
+25 32135530 1 6
+25 32135530 2 6
+25 32135530 3 6
+25 32135530 4 6
+25 32135530 5 6
+25 8529568 1 15
+25 8529568 2 15
+25 8529568 3 15
+25 8529568 4 15
+25 8529568 5 15
+25 29472599 1 15
+25 29472599 2 15
+25 29472599 3 15
+25 29472599 4 15
+25 29472599 5 15
+25 18752955 1 7
+25 18752955 2 7
+25 18752955 3 7
+25 18752955 4 7
+25 18752955 5 7
+25 7624970 1 12
+25 7624970 2 12
+25 7624970 3 12
+25 7624970 4 12
+25 7624970 5 12
+25 14450005 1 17
+25 14450005 2 17
+25 14450005 3 17
+25 14450005 4 17
+25 14450005 5 17
+25 5230955 1 1
+25 5230955 2 1
+25 5230955 3 1
+25 5230955 4 1
+25 5230955 5 1
+25 22090308 1 5
+25 22090308 2 5
+25 22090308 3 5
+25 22090308 4 5
+25 22090308 5 5
+25 19848608 1 9
+25 19848608 2 9
+25 19848608 3 9
+25 19848608 4 9
+25 19848608 5 9
+25 24404419 1 6
+25 24404419 2 6
+25 24404419 3 6
+25 24404419 4 6
+25 24404419 5 6
+25 29009514 1 14
+25 29009514 2 14
+25 29009514 3 14
+25 29009514 4 14
+25 29009514 5 14
+25 24460148 1 6
+25 24460148 2 6
+25 24460148 3 6
+25 24460148 4 6
+25 24460148 5 6
+25 20198351 1 10
+25 20198351 2 10
+25 20198351 3 10
+25 20198351 4 10
+25 20198351 5 10
+26 7084154 1 9
+26 7084154 2 9
+26 7084154 3 9
+26 7084154 4 9
+26 7084154 5 9
+26 25565466 1 9
+26 25565466 2 9
+26 25565466 3 9
+26 25565466 4 9
+26 25565466 5 9
+26 46816379 1 15
+26 46816379 2 15
+26 46816379 3 15
+26 46816379 4 15
+26 46816379 5 15
+26 21945765 1 1
+26 21945765 2 1
+26 21945765 3 1
+26 21945765 4 1
+26 21945765 5 1
+26 13640323 1 17
+26 13640323 2 17
+26 13640323 3 17
+26 13640323 4 17
+26 13640323 5 17
+26 30012262 1 13
+26 30012262 2 13
+26 30012262 3 13
+26 30012262 4 13
+26 30012262 5 13
+26 20042720 1 5
+26 20042720 2 5
+26 20042720 3 5
+26 20042720 4 5
+26 20042720 5 5
+26 16193914 1 6
+26 16193914 2 6
+26 16193914 3 6
+26 16193914 4 6
+26 16193914 5 6
+26 10183696 1 4
+26 10183696 2 4
+26 10183696 3 4
+26 10183696 4 4
+26 10183696 5 4
+26 24876252 1 0
+26 24876252 2 0
+26 24876252 3 0
+26 24876252 4 0
+26 24876252 5 0
+26 5209203 1 13
+26 5209203 2 13
+26 5209203 3 13
+26 5209203 4 13
+26 5209203 5 13
+26 18883903 1 17
+26 18883903 2 17
+26 18883903 3 17
+26 18883903 4 17
+26 18883903 5 17
+26 48312129 1 5
+26 48312129 2 5
+26 48312129 3 5
+26 48312129 4 5
+26 48312129 5 5
+26 24703773 1 7
+26 24703773 2 7
+26 24703773 3 7
+26 24703773 4 7
+26 24703773 5 7
+26 65103293 1 2
+26 65103293 2 2
+26 65103293 3 2
+26 65103293 4 2
+26 65103293 5 2
+26 64342799 1 8
+26 64342799 2 8
+26 64342799 3 8
+26 64342799 4 8
+26 64342799 5 8
+26 54033834 1 10
+26 54033834 2 10
+26 54033834 3 10
+26 54033834 4 10
+26 54033834 5 10
+26 11156063 1 17
+26 11156063 2 17
+26 11156063 3 17
+26 11156063 4 17
+26 11156063 5 17
+26 58182142 1 9
+26 58182142 2 9
+26 58182142 3 9
+26 58182142 4 9
+26 58182142 5 9
+26 25321691 1 10
+26 25321691 2 10
+26 25321691 3 10
+26 25321691 4 10
+26 25321691 5 10
+26 49670869 1 10
+26 49670869 2 10
+26 49670869 3 10
+26 49670869 4 10
+26 49670869 5 10
+26 9604075 1 6
+26 9604075 2 6
+26 9604075 3 6
+26 9604075 4 6
+26 9604075 5 6
+26 21246120 1 17
+26 21246120 2 17
+26 21246120 3 17
+26 21246120 4 17
+26 21246120 5 17
+26 54324966 1 15
+26 54324966 2 15
+26 54324966 3 15
+26 54324966 4 15
+26 54324966 5 15
+26 12222142 1 4
+26 12222142 2 4
+26 12222142 3 4
+26 12222142 4 4
+26 12222142 5 4
+26 46795936 1 10
+26 46795936 2 10
+26 46795936 3 10
+26 46795936 4 10
+26 46795936 5 10
+26 28991713 1 0
+26 28991713 2 0
+26 28991713 3 0
+26 28991713 4 0
+26 28991713 5 0
+26 21341767 1 6
+26 21341767 2 6
+26 21341767 3 6
+26 21341767 4 6
+26 21341767 5 6
+26 35735637 1 15
+26 35735637 2 15
+26 35735637 3 15
+26 35735637 4 15
+26 35735637 5 15
+26 20661103 1 13
+26 20661103 2 13
+26 20661103 3 13
+26 20661103 4 13
+26 20661103 5 13
+26 40707078 1 6
+26 40707078 2 6
+26 40707078 3 6
+26 40707078 4 6
+26 40707078 5 6
+26 53127018 1 12
+26 53127018 2 12
+26 53127018 3 12
+26 53127018 4 12
+26 53127018 5 12
+26 43370495 1 7
+26 43370495 2 7
+26 43370495 3 7
+26 43370495 4 7
+26 43370495 5 7
+26 4048861 1 10
+26 4048861 2 10
+26 4048861 3 10
+26 4048861 4 10
+26 4048861 5 10
+26 30464035 1 15
+26 30464035 2 15
+26 30464035 3 15
+26 30464035 4 15
+26 30464035 5 15
+26 5183631 1 9
+26 5183631 2 9
+26 5183631 3 9
+26 5183631 4 9
+26 5183631 5 9
+26 27077142 1 1
+26 27077142 2 1
+26 27077142 3 1
+26 27077142 4 1
+26 27077142 5 1
+26 48775300 1 6
+26 48775300 2 6
+26 48775300 3 6
+26 48775300 4 6
+26 48775300 5 6
+26 13488763 1 12
+26 13488763 2 12
+26 13488763 3 12
+26 13488763 4 12
+26 13488763 5 12
+26 13536330 1 8
+26 13536330 2 8
+26 13536330 3 8
+26 13536330 4 8
+26 13536330 5 8
+26 35410276 1 9
+26 35410276 2 9
+26 35410276 3 9
+26 35410276 4 9
+26 35410276 5 9
+26 53719442 1 12
+26 53719442 2 12
+26 53719442 3 12
+26 53719442 4 12
+26 53719442 5 12
+26 38572550 1 8
+26 38572550 2 8
+26 38572550 3 8
+26 38572550 4 8
+26 38572550 5 8
+26 66500609 1 4
+26 66500609 2 4
+26 66500609 3 4
+26 66500609 4 4
+26 66500609 5 4
+26 56930732 1 5
+26 56930732 2 5
+26 56930732 3 5
+26 56930732 4 5
+26 56930732 5 5
+26 13245256 1 7
+26 13245256 2 7
+26 13245256 3 7
+26 13245256 4 7
+26 13245256 5 7
+26 2474478 1 9
+26 2474478 2 9
+26 2474478 3 9
+26 2474478 4 9
+26 2474478 5 9
+26 47282801 1 12
+26 47282801 2 12
+26 47282801 3 12
+26 47282801 4 12
+26 47282801 5 12
+26 1178146 1 3
+26 1178146 2 3
+26 1178146 3 3
+26 1178146 4 3
+26 1178146 5 3
+26 43673724 1 6
+26 43673724 2 6
+26 43673724 3 6
+26 43673724 4 6
+26 43673724 5 6
+26 2100241 1 6
+26 2100241 2 6
+26 2100241 3 6
+26 2100241 4 6
+26 2100241 5 6
+26 41497130 1 0
+26 41497130 2 0
+26 41497130 3 0
+26 41497130 4 0
+26 41497130 5 0
+26 33722349 1 2
+26 33722349 2 2
+26 33722349 3 2
+26 33722349 4 2
+26 33722349 5 2
+26 9153815 1 12
+26 9153815 2 12
+26 9153815 3 12
+26 9153815 4 12
+26 9153815 5 12
+26 48610178 1 7
+26 48610178 2 7
+26 48610178 3 7
+26 48610178 4 7
+26 48610178 5 7
+26 53568526 1 14
+26 53568526 2 14
+26 53568526 3 14
+26 53568526 4 14
+26 53568526 5 14
+26 32823468 1 2
+26 32823468 2 2
+26 32823468 3 2
+26 32823468 4 2
+26 32823468 5 2
+26 65647768 1 14
+26 65647768 2 14
+26 65647768 3 14
+26 65647768 4 14
+26 65647768 5 14
+26 35401480 1 15
+26 35401480 2 15
+26 35401480 3 15
+26 35401480 4 15
+26 35401480 5 15
+26 41791958 1 12
+26 41791958 2 12
+26 41791958 3 12
+26 41791958 4 12
+26 41791958 5 12
+26 9655534 1 8
+26 9655534 2 8
+26 9655534 3 8
+26 9655534 4 8
+26 9655534 5 8
+26 40165520 1 1
+26 40165520 2 1
+26 40165520 3 1
+26 40165520 4 1
+26 40165520 5 1
+26 34020254 1 12
+26 34020254 2 12
+26 34020254 3 12
+26 34020254 4 12
+26 34020254 5 12
+26 61939853 1 8
+26 61939853 2 8
+26 61939853 3 8
+26 61939853 4 8
+26 61939853 5 8
+27 92315981 1 2
+27 92315981 2 2
+27 92315981 3 2
+27 92315981 4 2
+27 92315981 5 2
+27 61792721 1 8
+27 61792721 2 8
+27 61792721 3 8
+27 61792721 4 8
+27 61792721 5 8
+27 92388693 1 1
+27 92388693 2 1
+27 92388693 3 1
+27 92388693 4 1
+27 92388693 5 1
+27 53427871 1 17
+27 53427871 2 17
+27 53427871 3 17
+27 53427871 4 17
+27 53427871 5 17
+27 120842826 1 9
+27 120842826 2 9
+27 120842826 3 9
+27 120842826 4 9
+27 120842826 5 9
+27 28583319 1 10
+27 28583319 2 10
+27 28583319 3 10
+27 28583319 4 10
+27 28583319 5 10
+27 124744556 1 9
+27 124744556 2 9
+27 124744556 3 9
+27 124744556 4 9
+27 124744556 5 9
+27 4355438 1 0
+27 4355438 2 0
+27 4355438 3 0
+27 4355438 4 0
+27 4355438 5 0
+27 4216154 1 9
+27 4216154 2 9
+27 4216154 3 9
+27 4216154 4 9
+27 4216154 5 9
+27 123239172 1 13
+27 123239172 2 13
+27 123239172 3 13
+27 123239172 4 13
+27 123239172 5 13
+27 115756467 1 4
+27 115756467 2 4
+27 115756467 3 4
+27 115756467 4 4
+27 115756467 5 4
+27 51430308 1 9
+27 51430308 2 9
+27 51430308 3 9
+27 51430308 4 9
+27 51430308 5 9
+27 64209151 1 13
+27 64209151 2 13
+27 64209151 3 13
+27 64209151 4 13
+27 64209151 5 13
+27 86593418 1 6
+27 86593418 2 6
+27 86593418 3 6
+27 86593418 4 6
+27 86593418 5 6
+27 18520784 1 17
+27 18520784 2 17
+27 18520784 3 17
+27 18520784 4 17
+27 18520784 5 17
+27 99412133 1 3
+27 99412133 2 3
+27 99412133 3 3
+27 99412133 4 3
+27 99412133 5 3
+27 17075236 1 6
+27 17075236 2 6
+27 17075236 3 6
+27 17075236 4 6
+27 17075236 5 6
+27 9740701 1 10
+27 9740701 2 10
+27 9740701 3 10
+27 9740701 4 10
+27 9740701 5 10
+27 42355725 1 17
+27 42355725 2 17
+27 42355725 3 17
+27 42355725 4 17
+27 42355725 5 17
+27 76792086 1 12
+27 76792086 2 12
+27 76792086 3 12
+27 76792086 4 12
+27 76792086 5 12
+27 34848403 1 4
+27 34848403 2 4
+27 34848403 3 4
+27 34848403 4 4
+27 34848403 5 4
+27 60857654 1 4
+27 60857654 2 4
+27 60857654 3 4
+27 60857654 4 4
+27 60857654 5 4
+27 89466329 1 1
+27 89466329 2 1
+27 89466329 3 1
+27 89466329 4 1
+27 89466329 5 1
+27 7416677 1 0
+27 7416677 2 0
+27 7416677 3 0
+27 7416677 4 0
+27 7416677 5 0
+27 94093693 1 17
+27 94093693 2 17
+27 94093693 3 17
+27 94093693 4 17
+27 94093693 5 17
+27 71977043 1 0
+27 71977043 2 0
+27 71977043 3 0
+27 71977043 4 0
+27 71977043 5 0
+27 32931909 1 1
+27 32931909 2 1
+27 32931909 3 1
+27 32931909 4 1
+27 32931909 5 1
+27 99417150 1 1
+27 99417150 2 1
+27 99417150 3 1
+27 99417150 4 1
+27 99417150 5 1
+27 78489591 1 5
+27 78489591 2 5
+27 78489591 3 5
+27 78489591 4 5
+27 78489591 5 5
+27 56442740 1 17
+27 56442740 2 17
+27 56442740 3 17
+27 56442740 4 17
+27 56442740 5 17
+27 49715079 1 8
+27 49715079 2 8
+27 49715079 3 8
+27 49715079 4 8
+27 49715079 5 8
+27 95552279 1 5
+27 95552279 2 5
+27 95552279 3 5
+27 95552279 4 5
+27 95552279 5 5
+27 119474039 1 13
+27 119474039 2 13
+27 119474039 3 13
+27 119474039 4 13
+27 119474039 5 13
+27 47612448 1 12
+27 47612448 2 12
+27 47612448 3 12
+27 47612448 4 12
+27 47612448 5 12
+27 125922426 1 14
+27 125922426 2 14
+27 125922426 3 14
+27 125922426 4 14
+27 125922426 5 14
+27 18947749 1 8
+27 18947749 2 8
+27 18947749 3 8
+27 18947749 4 8
+27 18947749 5 8
+27 92954715 1 5
+27 92954715 2 5
+27 92954715 3 5
+27 92954715 4 5
+27 92954715 5 5
+27 69488478 1 7
+27 69488478 2 7
+27 69488478 3 7
+27 69488478 4 7
+27 69488478 5 7
+27 36779293 1 0
+27 36779293 2 0
+27 36779293 3 0
+27 36779293 4 0
+27 36779293 5 0
+27 90333541 1 4
+27 90333541 2 4
+27 90333541 3 4
+27 90333541 4 4
+27 90333541 5 4
+27 113514082 1 1
+27 113514082 2 1
+27 113514082 3 1
+27 113514082 4 1
+27 113514082 5 1
+27 114627133 1 2
+27 114627133 2 2
+27 114627133 3 2
+27 114627133 4 2
+27 114627133 5 2
+27 67788048 1 12
+27 67788048 2 12
+27 67788048 3 12
+27 67788048 4 12
+27 67788048 5 12
+27 80102932 1 6
+27 80102932 2 6
+27 80102932 3 6
+27 80102932 4 6
+27 80102932 5 6
+27 80083249 1 4
+27 80083249 2 4
+27 80083249 3 4
+27 80083249 4 4
+27 80083249 5 4
+27 8871500 1 0
+27 8871500 2 0
+27 8871500 3 0
+27 8871500 4 0
+27 8871500 5 0
+27 96933402 1 10
+27 96933402 2 10
+27 96933402 3 10
+27 96933402 4 10
+27 96933402 5 10
+27 40432695 1 17
+27 40432695 2 17
+27 40432695 3 17
+27 40432695 4 17
+27 40432695 5 17
+27 55794895 1 13
+27 55794895 2 13
+27 55794895 3 13
+27 55794895 4 13
+27 55794895 5 13
+27 120388642 1 6
+27 120388642 2 6
+27 120388642 3 6
+27 120388642 4 6
+27 120388642 5 6
+27 64256165 1 0
+27 64256165 2 0
+27 64256165 3 0
+27 64256165 4 0
+27 64256165 5 0
+27 4822164 1 0
+27 4822164 2 0
+27 4822164 3 0
+27 4822164 4 0
+27 4822164 5 0
+27 14139945 1 12
+27 14139945 2 12
+27 14139945 3 12
+27 14139945 4 12
+27 14139945 5 12
+27 116590039 1 0
+27 116590039 2 0
+27 116590039 3 0
+27 116590039 4 0
+27 116590039 5 0
+27 61027392 1 6
+27 61027392 2 6
+27 61027392 3 6
+27 61027392 4 6
+27 61027392 5 6
+27 71808439 1 4
+27 71808439 2 4
+27 71808439 3 4
+27 71808439 4 4
+27 71808439 5 4
+27 4329359 1 4
+27 4329359 2 4
+27 4329359 3 4
+27 4329359 4 4
+27 4329359 5 4
+27 90248073 1 2
+27 90248073 2 2
+27 90248073 3 2
+27 90248073 4 2
+27 90248073 5 2
+27 53334044 1 17
+27 53334044 2 17
+27 53334044 3 17
+27 53334044 4 17
+27 53334044 5 17
+27 79216751 1 12
+27 79216751 2 12
+27 79216751 3 12
+27 79216751 4 12
+27 79216751 5 12
+27 14571829 1 6
+27 14571829 2 6
+27 14571829 3 6
+27 14571829 4 6
+27 14571829 5 6
+27 58816473 1 5
+27 58816473 2 5
+27 58816473 3 5
+27 58816473 4 5
+27 58816473 5 5
+27 97942416 1 15
+27 97942416 2 15
+27 97942416 3 15
+27 97942416 4 15
+27 97942416 5 15
+27 25656398 1 9
+27 25656398 2 9
+27 25656398 3 9
+27 25656398 4 9
+27 25656398 5 9
+28 115821936 1 15
+28 115821936 2 15
+28 115821936 3 15
+28 115821936 4 15
+28 115821936 5 15
+28 108711265 1 3
+28 108711265 2 3
+28 108711265 3 3
+28 108711265 4 3
+28 108711265 5 3
+28 51814809 1 8
+28 51814809 2 8
+28 51814809 3 8
+28 51814809 4 8
+28 51814809 5 8
+28 9511812 1 3
+28 9511812 2 3
+28 9511812 3 3
+28 9511812 4 3
+28 9511812 5 3
+28 119984430 1 14
+28 119984430 2 14
+28 119984430 3 14
+28 119984430 4 14
+28 119984430 5 14
+28 222765195 1 1
+28 222765195 2 1
+28 222765195 3 1
+28 222765195 4 1
+28 222765195 5 1
+28 44273960 1 13
+28 44273960 2 13
+28 44273960 3 13
+28 44273960 4 13
+28 44273960 5 13
+28 146489653 1 8
+28 146489653 2 8
+28 146489653 3 8
+28 146489653 4 8
+28 146489653 5 8
+28 242813898 1 9
+28 242813898 2 9
+28 242813898 3 9
+28 242813898 4 9
+28 242813898 5 9
+28 145291726 1 6
+28 145291726 2 6
+28 145291726 3 6
+28 145291726 4 6
+28 145291726 5 6
+28 64513013 1 1
+28 64513013 2 1
+28 64513013 3 1
+28 64513013 4 1
+28 64513013 5 1
+28 214162337 1 13
+28 214162337 2 13
+28 214162337 3 13
+28 214162337 4 13
+28 214162337 5 13
+28 210803129 1 2
+28 210803129 2 2
+28 210803129 3 2
+28 210803129 4 2
+28 210803129 5 2
+28 60497323 1 5
+28 60497323 2 5
+28 60497323 3 5
+28 60497323 4 5
+28 60497323 5 5
+28 188261423 1 9
+28 188261423 2 9
+28 188261423 3 9
+28 188261423 4 9
+28 188261423 5 9
+28 140541072 1 14
+28 140541072 2 14
+28 140541072 3 14
+28 140541072 4 14
+28 140541072 5 14
+28 33608837 1 17
+28 33608837 2 17
+28 33608837 3 17
+28 33608837 4 17
+28 33608837 5 17
+28 69772754 1 10
+28 69772754 2 10
+28 69772754 3 10
+28 69772754 4 10
+28 69772754 5 10
+28 231659097 1 3
+28 231659097 2 3
+28 231659097 3 3
+28 231659097 4 3
+28 231659097 5 3
+28 65708608 1 4
+28 65708608 2 4
+28 65708608 3 4
+28 65708608 4 4
+28 65708608 5 4
+28 27844939 1 5
+28 27844939 2 5
+28 27844939 3 5
+28 27844939 4 5
+28 27844939 5 5
+28 250016684 1 1
+28 250016684 2 1
+28 250016684 3 1
+28 250016684 4 1
+28 250016684 5 1
+28 27914189 1 10
+28 27914189 2 10
+28 27914189 3 10
+28 27914189 4 10
+28 27914189 5 10
+28 242637280 1 2
+28 242637280 2 2
+28 242637280 3 2
+28 242637280 4 2
+28 242637280 5 2
+28 100798268 1 4
+28 100798268 2 4
+28 100798268 3 4
+28 100798268 4 4
+28 100798268 5 4
+28 63664849 1 2
+28 63664849 2 2
+28 63664849 3 2
+28 63664849 4 2
+28 63664849 5 2
+28 186850612 1 9
+28 186850612 2 9
+28 186850612 3 9
+28 186850612 4 9
+28 186850612 5 9
+28 154249749 1 3
+28 154249749 2 3
+28 154249749 3 3
+28 154249749 4 3
+28 154249749 5 3
+28 90932767 1 8
+28 90932767 2 8
+28 90932767 3 8
+28 90932767 4 8
+28 90932767 5 8
+28 101133202 1 7
+28 101133202 2 7
+28 101133202 3 7
+28 101133202 4 7
+28 101133202 5 7
+28 161863951 1 13
+28 161863951 2 13
+28 161863951 3 13
+28 161863951 4 13
+28 161863951 5 13
+28 106351991 1 13
+28 106351991 2 13
+28 106351991 3 13
+28 106351991 4 13
+28 106351991 5 13
+28 164447437 1 6
+28 164447437 2 6
+28 164447437 3 6
+28 164447437 4 6
+28 164447437 5 6
+28 198321520 1 8
+28 198321520 2 8
+28 198321520 3 8
+28 198321520 4 8
+28 198321520 5 8
+28 66343474 1 5
+28 66343474 2 5
+28 66343474 3 5
+28 66343474 4 5
+28 66343474 5 5
+28 221986069 1 14
+28 221986069 2 14
+28 221986069 3 14
+28 221986069 4 14
+28 221986069 5 14
+28 19689396 1 0
+28 19689396 2 0
+28 19689396 3 0
+28 19689396 4 0
+28 19689396 5 0
+28 105945506 1 12
+28 105945506 2 12
+28 105945506 3 12
+28 105945506 4 12
+28 105945506 5 12
+28 153231939 1 9
+28 153231939 2 9
+28 153231939 3 9
+28 153231939 4 9
+28 153231939 5 9
+28 205884141 1 10
+28 205884141 2 10
+28 205884141 3 10
+28 205884141 4 10
+28 205884141 5 10
+28 101379925 1 0
+28 101379925 2 0
+28 101379925 3 0
+28 101379925 4 0
+28 101379925 5 0
+28 217838996 1 0
+28 217838996 2 0
+28 217838996 3 0
+28 217838996 4 0
+28 217838996 5 0
+28 146756671 1 10
+28 146756671 2 10
+28 146756671 3 10
+28 146756671 4 10
+28 146756671 5 10
+28 13896821 1 2
+28 13896821 2 2
+28 13896821 3 2
+28 13896821 4 2
+28 13896821 5 2
+28 262954695 1 8
+28 262954695 2 8
+28 262954695 3 8
+28 262954695 4 8
+28 262954695 5 8
+28 188329314 1 14
+28 188329314 2 14
+28 188329314 3 14
+28 188329314 4 14
+28 188329314 5 14
+28 166574838 1 12
+28 166574838 2 12
+28 166574838 3 12
+28 166574838 4 12
+28 166574838 5 12
+28 73291029 1 10
+28 73291029 2 10
+28 73291029 3 10
+28 73291029 4 10
+28 73291029 5 10
+28 60443185 1 17
+28 60443185 2 17
+28 60443185 3 17
+28 60443185 4 17
+28 60443185 5 17
+28 168418913 1 14
+28 168418913 2 14
+28 168418913 3 14
+28 168418913 4 14
+28 168418913 5 14
+28 106600330 1 4
+28 106600330 2 4
+28 106600330 3 4
+28 106600330 4 4
+28 106600330 5 4
+28 224100522 1 13
+28 224100522 2 13
+28 224100522 3 13
+28 224100522 4 13
+28 224100522 5 13
+28 50445651 1 13
+28 50445651 2 13
+28 50445651 3 13
+28 50445651 4 13
+28 50445651 5 13
+28 49791383 1 0
+28 49791383 2 0
+28 49791383 3 0
+28 49791383 4 0
+28 49791383 5 0
+28 56004596 1 7
+28 56004596 2 7
+28 56004596 3 7
+28 56004596 4 7
+28 56004596 5 7
+28 163008005 1 9
+28 163008005 2 9
+28 163008005 3 9
+28 163008005 4 9
+28 163008005 5 9
+28 130294270 1 8
+28 130294270 2 8
+28 130294270 3 8
+28 130294270 4 8
+28 130294270 5 8
+28 79031870 1 7
+28 79031870 2 7
+28 79031870 3 7
+28 79031870 4 7
+28 79031870 5 7
+28 8779135 1 7
+28 8779135 2 7
+28 8779135 3 7
+28 8779135 4 7
+28 8779135 5 7
+28 132122986 1 3
+28 132122986 2 3
+28 132122986 3 3
+28 132122986 4 3
+28 132122986 5 3
+28 106262167 1 3
+28 106262167 2 3
+28 106262167 3 3
+28 106262167 4 3
+28 106262167 5 3
+28 84962373 1 14
+28 84962373 2 14
+28 84962373 3 14
+28 84962373 4 14
+28 84962373 5 14
+28 149117771 1 2
+28 149117771 2 2
+28 149117771 3 2
+28 149117771 4 2
+28 149117771 5 2
+28 179783442 1 15
+28 179783442 2 15
+28 179783442 3 15
+28 179783442 4 15
+28 179783442 5 15
+29 335271491 1 6
+29 335271491 2 6
+29 335271491 3 6
+29 335271491 4 6
+29 335271491 5 6
+29 10720791 1 17
+29 10720791 2 17
+29 10720791 3 17
+29 10720791 4 17
+29 10720791 5 17
+29 500040308 1 0
+29 500040308 2 0
+29 500040308 3 0
+29 500040308 4 0
+29 500040308 5 0
+29 510755966 1 8
+29 510755966 2 8
+29 510755966 3 8
+29 510755966 4 8
+29 510755966 5 8
+29 227186933 1 15
+29 227186933 2 15
+29 227186933 3 15
+29 227186933 4 15
+29 227186933 5 15
+29 422662843 1 13
+29 422662843 2 13
+29 422662843 3 13
+29 422662843 4 13
+29 422662843 5 13
+29 81866932 1 3
+29 81866932 2 3
+29 81866932 3 3
+29 81866932 4 3
+29 81866932 5 3
+29 470195498 1 9
+29 470195498 2 9
+29 470195498 3 9
+29 470195498 4 9
+29 470195498 5 9
+29 505281812 1 6
+29 505281812 2 6
+29 505281812 3 6
+29 505281812 4 6
+29 505281812 5 6
+29 42328055 1 17
+29 42328055 2 17
+29 42328055 3 17
+29 42328055 4 17
+29 42328055 5 17
+29 510604597 1 4
+29 510604597 2 4
+29 510604597 3 4
+29 510604597 4 4
+29 510604597 5 4
+29 380926471 1 10
+29 380926471 2 10
+29 380926471 3 10
+29 380926471 4 10
+29 380926471 5 10
+29 159591288 1 5
+29 159591288 2 5
+29 159591288 3 5
+29 159591288 4 5
+29 159591288 5 5
+29 189495832 1 13
+29 189495832 2 13
+29 189495832 3 13
+29 189495832 4 13
+29 189495832 5 13
+29 7461185 1 1
+29 7461185 2 1
+29 7461185 3 1
+29 7461185 4 1
+29 7461185 5 1
+29 41392678 1 15
+29 41392678 2 15
+29 41392678 3 15
+29 41392678 4 15
+29 41392678 5 15
+29 466412287 1 7
+29 466412287 2 7
+29 466412287 3 7
+29 466412287 4 7
+29 466412287 5 7
+29 269683984 1 10
+29 269683984 2 10
+29 269683984 3 10
+29 269683984 4 10
+29 269683984 5 10
+29 81614953 1 14
+29 81614953 2 14
+29 81614953 3 14
+29 81614953 4 14
+29 81614953 5 14
+29 117179003 1 4
+29 117179003 2 4
+29 117179003 3 4
+29 117179003 4 4
+29 117179003 5 4
+29 348566793 1 17
+29 348566793 2 17
+29 348566793 3 17
+29 348566793 4 17
+29 348566793 5 17
+29 502596854 1 4
+29 502596854 2 4
+29 502596854 3 4
+29 502596854 4 4
+29 502596854 5 4
+29 364569853 1 17
+29 364569853 2 17
+29 364569853 3 17
+29 364569853 4 17
+29 364569853 5 17
+29 262837855 1 5
+29 262837855 2 5
+29 262837855 3 5
+29 262837855 4 5
+29 262837855 5 5
+29 316887548 1 10
+29 316887548 2 10
+29 316887548 3 10
+29 316887548 4 10
+29 316887548 5 10
+29 223063684 1 4
+29 223063684 2 4
+29 223063684 3 4
+29 223063684 4 4
+29 223063684 5 4
+29 459226263 1 15
+29 459226263 2 15
+29 459226263 3 15
+29 459226263 4 15
+29 459226263 5 15
+29 299433996 1 5
+29 299433996 2 5
+29 299433996 3 5
+29 299433996 4 5
+29 299433996 5 5
+29 200795585 1 15
+29 200795585 2 15
+29 200795585 3 15
+29 200795585 4 15
+29 200795585 5 15
+29 136914840 1 13
+29 136914840 2 13
+29 136914840 3 13
+29 136914840 4 13
+29 136914840 5 13
+29 237980817 1 17
+29 237980817 2 17
+29 237980817 3 17
+29 237980817 4 17
+29 237980817 5 17
+29 350103844 1 14
+29 350103844 2 14
+29 350103844 3 14
+29 350103844 4 14
+29 350103844 5 14
+29 441877573 1 3
+29 441877573 2 3
+29 441877573 3 3
+29 441877573 4 3
+29 441877573 5 3
+29 40558515 1 10
+29 40558515 2 10
+29 40558515 3 10
+29 40558515 4 10
+29 40558515 5 10
+29 161801865 1 7
+29 161801865 2 7
+29 161801865 3 7
+29 161801865 4 7
+29 161801865 5 7
+29 504185643 1 5
+29 504185643 2 5
+29 504185643 3 5
+29 504185643 4 5
+29 504185643 5 5
+29 85566969 1 13
+29 85566969 2 13
+29 85566969 3 13
+29 85566969 4 13
+29 85566969 5 13
+29 59549821 1 0
+29 59549821 2 0
+29 59549821 3 0
+29 59549821 4 0
+29 59549821 5 0
+29 42304740 1 6
+29 42304740 2 6
+29 42304740 3 6
+29 42304740 4 6
+29 42304740 5 6
+29 14245896 1 6
+29 14245896 2 6
+29 14245896 3 6
+29 14245896 4 6
+29 14245896 5 6
+29 313701459 1 12
+29 313701459 2 12
+29 313701459 3 12
+29 313701459 4 12
+29 313701459 5 12
+29 77420095 1 6
+29 77420095 2 6
+29 77420095 3 6
+29 77420095 4 6
+29 77420095 5 6
+29 243081033 1 1
+29 243081033 2 1
+29 243081033 3 1
+29 243081033 4 1
+29 243081033 5 1
+29 430152328 1 10
+29 430152328 2 10
+29 430152328 3 10
+29 430152328 4 10
+29 430152328 5 10
+29 84780619 1 17
+29 84780619 2 17
+29 84780619 3 17
+29 84780619 4 17
+29 84780619 5 17
+29 251064423 1 5
+29 251064423 2 5
+29 251064423 3 5
+29 251064423 4 5
+29 251064423 5 5
+29 529469218 1 13
+29 529469218 2 13
+29 529469218 3 13
+29 529469218 4 13
+29 529469218 5 13
+29 133549787 1 12
+29 133549787 2 12
+29 133549787 3 12
+29 133549787 4 12
+29 133549787 5 12
+29 383495391 1 2
+29 383495391 2 2
+29 383495391 3 2
+29 383495391 4 2
+29 383495391 5 2
+29 446460424 1 1
+29 446460424 2 1
+29 446460424 3 1
+29 446460424 4 1
+29 446460424 5 1
+29 302973982 1 15
+29 302973982 2 15
+29 302973982 3 15
+29 302973982 4 15
+29 302973982 5 15
+29 321643285 1 2
+29 321643285 2 2
+29 321643285 3 2
+29 321643285 4 2
+29 321643285 5 2
+29 299298703 1 17
+29 299298703 2 17
+29 299298703 3 17
+29 299298703 4 17
+29 299298703 5 17
+29 90118743 1 13
+29 90118743 2 13
+29 90118743 3 13
+29 90118743 4 13
+29 90118743 5 13
+29 269748402 1 5
+29 269748402 2 5
+29 269748402 3 5
+29 269748402 4 5
+29 269748402 5 5
+29 47030190 1 6
+29 47030190 2 6
+29 47030190 3 6
+29 47030190 4 6
+29 47030190 5 6
+29 504453345 1 14
+29 504453345 2 14
+29 504453345 3 14
+29 504453345 4 14
+29 504453345 5 14
+29 506285359 1 10
+29 506285359 2 10
+29 506285359 3 10
+29 506285359 4 10
+29 506285359 5 10
+29 429364883 1 0
+29 429364883 2 0
+29 429364883 3 0
+29 429364883 4 0
+29 429364883 5 0
+29 437983235 1 3
+29 437983235 2 3
+29 437983235 3 3
+29 437983235 4 3
+29 437983235 5 3
+29 446722782 1 1
+29 446722782 2 1
+29 446722782 3 1
+29 446722782 4 1
+29 446722782 5 1
+29 170722190 1 5
+29 170722190 2 5
+29 170722190 3 5
+29 170722190 4 5
+29 170722190 5 5
+29 347257661 1 1
+29 347257661 2 1
+29 347257661 3 1
+29 347257661 4 1
+29 347257661 5 1
+29 344826579 1 3
+29 344826579 2 3
+29 344826579 3 3
+29 344826579 4 3
+29 344826579 5 3
+30 213793736 1 17
+30 213793736 2 17
+30 213793736 3 17
+30 213793736 4 17
+30 213793736 5 17
+30 841563124 1 8
+30 841563124 2 8
+30 841563124 3 8
+30 841563124 4 8
+30 841563124 5 8
+30 497541093 1 0
+30 497541093 2 0
+30 497541093 3 0
+30 497541093 4 0
+30 497541093 5 0
+30 886071695 1 4
+30 886071695 2 4
+30 886071695 3 4
+30 886071695 4 4
+30 886071695 5 4
+30 442450336 1 15
+30 442450336 2 15
+30 442450336 3 15
+30 442450336 4 15
+30 442450336 5 15
+30 359840809 1 1
+30 359840809 2 1
+30 359840809 3 1
+30 359840809 4 1
+30 359840809 5 1
+30 237523472 1 7
+30 237523472 2 7
+30 237523472 3 7
+30 237523472 4 7
+30 237523472 5 7
+30 841255244 1 5
+30 841255244 2 5
+30 841255244 3 5
+30 841255244 4 5
+30 841255244 5 5
+30 254748983 1 7
+30 254748983 2 7
+30 254748983 3 7
+30 254748983 4 7
+30 254748983 5 7
+30 888089982 1 9
+30 888089982 2 9
+30 888089982 3 9
+30 888089982 4 9
+30 888089982 5 9
+30 514507124 1 17
+30 514507124 2 17
+30 514507124 3 17
+30 514507124 4 17
+30 514507124 5 17
+30 954375894 1 0
+30 954375894 2 0
+30 954375894 3 0
+30 954375894 4 0
+30 954375894 5 0
+30 313226812 1 1
+30 313226812 2 1
+30 313226812 3 1
+30 313226812 4 1
+30 313226812 5 1
+30 339371217 1 15
+30 339371217 2 15
+30 339371217 3 15
+30 339371217 4 15
+30 339371217 5 15
+30 818297353 1 4
+30 818297353 2 4
+30 818297353 3 4
+30 818297353 4 4
+30 818297353 5 4
+30 70402405 1 5
+30 70402405 2 5
+30 70402405 3 5
+30 70402405 4 5
+30 70402405 5 5
+30 778614673 1 10
+30 778614673 2 10
+30 778614673 3 10
+30 778614673 4 10
+30 778614673 5 10
+30 475256662 1 14
+30 475256662 2 14
+30 475256662 3 14
+30 475256662 4 14
+30 475256662 5 14
+30 263311931 1 2
+30 263311931 2 2
+30 263311931 3 2
+30 263311931 4 2
+30 263311931 5 2
+30 499638729 1 3
+30 499638729 2 3
+30 499638729 3 3
+30 499638729 4 3
+30 499638729 5 3
+30 191707598 1 9
+30 191707598 2 9
+30 191707598 3 9
+30 191707598 4 9
+30 191707598 5 9
+30 13291798 1 17
+30 13291798 2 17
+30 13291798 3 17
+30 13291798 4 17
+30 13291798 5 17
+30 428344683 1 2
+30 428344683 2 2
+30 428344683 3 2
+30 428344683 4 2
+30 428344683 5 2
+30 470671586 1 14
+30 470671586 2 14
+30 470671586 3 14
+30 470671586 4 14
+30 470671586 5 14
+30 1010796989 1 7
+30 1010796989 2 7
+30 1010796989 3 7
+30 1010796989 4 7
+30 1010796989 5 7
+30 550173547 1 5
+30 550173547 2 5
+30 550173547 3 5
+30 550173547 4 5
+30 550173547 5 5
+30 984276590 1 3
+30 984276590 2 3
+30 984276590 3 3
+30 984276590 4 3
+30 984276590 5 3
+30 400752165 1 15
+30 400752165 2 15
+30 400752165 3 15
+30 400752165 4 15
+30 400752165 5 15
+30 676513500 1 0
+30 676513500 2 0
+30 676513500 3 0
+30 676513500 4 0
+30 676513500 5 0
+30 29569926 1 13
+30 29569926 2 13
+30 29569926 3 13
+30 29569926 4 13
+30 29569926 5 13
+30 814936588 1 2
+30 814936588 2 2
+30 814936588 3 2
+30 814936588 4 2
+30 814936588 5 2
+30 424154654 1 1
+30 424154654 2 1
+30 424154654 3 1
+30 424154654 4 1
+30 424154654 5 1
+30 414893534 1 1
+30 414893534 2 1
+30 414893534 3 1
+30 414893534 4 1
+30 414893534 5 1
+30 1050718441 1 6
+30 1050718441 2 6
+30 1050718441 3 6
+30 1050718441 4 6
+30 1050718441 5 6
+30 680733058 1 8
+30 680733058 2 8
+30 680733058 3 8
+30 680733058 4 8
+30 680733058 5 8
+30 194457832 1 13
+30 194457832 2 13
+30 194457832 3 13
+30 194457832 4 13
+30 194457832 5 13
+30 961676074 1 3
+30 961676074 2 3
+30 961676074 3 3
+30 961676074 4 3
+30 961676074 5 3
+30 735607789 1 15
+30 735607789 2 15
+30 735607789 3 15
+30 735607789 4 15
+30 735607789 5 15
+30 375086337 1 6
+30 375086337 2 6
+30 375086337 3 6
+30 375086337 4 6
+30 375086337 5 6
+30 52289719 1 0
+30 52289719 2 0
+30 52289719 3 0
+30 52289719 4 0
+30 52289719 5 0
+30 482043226 1 1
+30 482043226 2 1
+30 482043226 3 1
+30 482043226 4 1
+30 482043226 5 1
+30 1035547710 1 4
+30 1035547710 2 4
+30 1035547710 3 4
+30 1035547710 4 4
+30 1035547710 5 4
+30 222543404 1 10
+30 222543404 2 10
+30 222543404 3 10
+30 222543404 4 10
+30 222543404 5 10
+30 1060433998 1 2
+30 1060433998 2 2
+30 1060433998 3 2
+30 1060433998 4 2
+30 1060433998 5 2
+30 887738302 1 7
+30 887738302 2 7
+30 887738302 3 7
+30 887738302 4 7
+30 887738302 5 7
+30 868165466 1 0
+30 868165466 2 0
+30 868165466 3 0
+30 868165466 4 0
+30 868165466 5 0
+30 1051398814 1 8
+30 1051398814 2 8
+30 1051398814 3 8
+30 1051398814 4 8
+30 1051398814 5 8
+30 489644425 1 6
+30 489644425 2 6
+30 489644425 3 6
+30 489644425 4 6
+30 489644425 5 6
+30 1024951511 1 15
+30 1024951511 2 15
+30 1024951511 3 15
+30 1024951511 4 15
+30 1024951511 5 15
+30 686077717 1 15
+30 686077717 2 15
+30 686077717 3 15
+30 686077717 4 15
+30 686077717 5 15
+30 1056030306 1 0
+30 1056030306 2 0
+30 1056030306 3 0
+30 1056030306 4 0
+30 1056030306 5 0
+30 565885909 1 8
+30 565885909 2 8
+30 565885909 3 8
+30 565885909 4 8
+30 565885909 5 8
+30 89610460 1 9
+30 89610460 2 9
+30 89610460 3 9
+30 89610460 4 9
+30 89610460 5 9
+30 774443031 1 2
+30 774443031 2 2
+30 774443031 3 2
+30 774443031 4 2
+30 774443031 5 2
+30 433823353 1 15
+30 433823353 2 15
+30 433823353 3 15
+30 433823353 4 15
+30 433823353 5 15
+30 394963635 1 3
+30 394963635 2 3
+30 394963635 3 3
+30 394963635 4 3
+30 394963635 5 3
+30 724153400 1 14
+30 724153400 2 14
+30 724153400 3 14
+30 724153400 4 14
+30 724153400 5 14
+30 29831260 1 4
+30 29831260 2 4
+30 29831260 3 4
+30 29831260 4 4
+30 29831260 5 4
+30 241349464 1 9
+30 241349464 2 9
+30 241349464 3 9
+30 241349464 4 9
+30 241349464 5 9
+30 57273401 1 3
+30 57273401 2 3
+30 57273401 3 3
+30 57273401 4 3
+30 57273401 5 3
+30 230647305 1 2
+30 230647305 2 2
+30 230647305 3 2
+30 230647305 4 2
+30 230647305 5 2
+30 181878195 1 15
+30 181878195 2 15
+30 181878195 3 15
+30 181878195 4 15
+30 181878195 5 15
+30 21273447 1 12
+30 21273447 2 12
+30 21273447 3 12
+30 21273447 4 12
+30 21273447 5 12
+30 386568080 1 6
+30 386568080 2 6
+30 386568080 3 6
+30 386568080 4 6
+30 386568080 5 6
+31 433243292 1 4
+31 433243292 2 4
+31 433243292 3 4
+31 433243292 4 4
+31 433243292 5 4
+31 743572650 1 9
+31 743572650 2 9
+31 743572650 3 9
+31 743572650 4 9
+31 743572650 5 9
+31 1751072959 1 3
+31 1751072959 2 3
+31 1751072959 3 3
+31 1751072959 4 3
+31 1751072959 5 3
+31 582009481 1 13
+31 582009481 2 13
+31 582009481 3 13
+31 582009481 4 13
+31 582009481 5 13
+31 1086523751 1 5
+31 1086523751 2 5
+31 1086523751 3 5
+31 1086523751 4 5
+31 1086523751 5 5
+31 1633480282 1 13
+31 1633480282 2 13
+31 1633480282 3 13
+31 1633480282 4 13
+31 1633480282 5 13
+31 543551900 1 8
+31 543551900 2 8
+31 543551900 3 8
+31 543551900 4 8
+31 543551900 5 8
+31 359654721 1 14
+31 359654721 2 14
+31 359654721 3 14
+31 359654721 4 14
+31 359654721 5 14
+31 517216897 1 8
+31 517216897 2 8
+31 517216897 3 8
+31 517216897 4 8
+31 517216897 5 8
+31 1321997222 1 7
+31 1321997222 2 7
+31 1321997222 3 7
+31 1321997222 4 7
+31 1321997222 5 7
+31 1765905076 1 10
+31 1765905076 2 10
+31 1765905076 3 10
+31 1765905076 4 10
+31 1765905076 5 10
+31 1658010939 1 2
+31 1658010939 2 2
+31 1658010939 3 2
+31 1658010939 4 2
+31 1658010939 5 2
+31 798885882 1 4
+31 798885882 2 4
+31 798885882 3 4
+31 798885882 4 4
+31 798885882 5 4
+31 1542111550 1 6
+31 1542111550 2 6
+31 1542111550 3 6
+31 1542111550 4 6
+31 1542111550 5 6
+31 1979674396 1 15
+31 1979674396 2 15
+31 1979674396 3 15
+31 1979674396 4 15
+31 1979674396 5 15
+31 1313431291 1 14
+31 1313431291 2 14
+31 1313431291 3 14
+31 1313431291 4 14
+31 1313431291 5 14
+31 1748289035 1 10
+31 1748289035 2 10
+31 1748289035 3 10
+31 1748289035 4 10
+31 1748289035 5 10
+31 2017345172 1 12
+31 2017345172 2 12
+31 2017345172 3 12
+31 2017345172 4 12
+31 2017345172 5 12
+31 1992315978 1 9
+31 1992315978 2 9
+31 1992315978 3 9
+31 1992315978 4 9
+31 1992315978 5 9
+31 1624850948 1 17
+31 1624850948 2 17
+31 1624850948 3 17
+31 1624850948 4 17
+31 1624850948 5 17
+31 780864908 1 15
+31 780864908 2 15
+31 780864908 3 15
+31 780864908 4 15
+31 780864908 5 15
+31 534307425 1 17
+31 534307425 2 17
+31 534307425 3 17
+31 534307425 4 17
+31 534307425 5 17
+31 1301871260 1 7
+31 1301871260 2 7
+31 1301871260 3 7
+31 1301871260 4 7
+31 1301871260 5 7
+31 222436705 1 6
+31 222436705 2 6
+31 222436705 3 6
+31 222436705 4 6
+31 222436705 5 6
+31 421579900 1 4
+31 421579900 2 4
+31 421579900 3 4
+31 421579900 4 4
+31 421579900 5 4
+31 2051749662 1 15
+31 2051749662 2 15
+31 2051749662 3 15
+31 2051749662 4 15
+31 2051749662 5 15
+31 1525087697 1 1
+31 1525087697 2 1
+31 1525087697 3 1
+31 1525087697 4 1
+31 1525087697 5 1
+31 9065501 1 7
+31 9065501 2 7
+31 9065501 3 7
+31 9065501 4 7
+31 9065501 5 7
+31 1054811774 1 14
+31 1054811774 2 14
+31 1054811774 3 14
+31 1054811774 4 14
+31 1054811774 5 14
+31 1675964300 1 5
+31 1675964300 2 5
+31 1675964300 3 5
+31 1675964300 4 5
+31 1675964300 5 5
+31 85747085 1 3
+31 85747085 2 3
+31 85747085 3 3
+31 85747085 4 3
+31 85747085 5 3
+31 2010083787 1 12
+31 2010083787 2 12
+31 2010083787 3 12
+31 2010083787 4 12
+31 2010083787 5 12
+31 960759126 1 1
+31 960759126 2 1
+31 960759126 3 1
+31 960759126 4 1
+31 960759126 5 1
+31 892955437 1 7
+31 892955437 2 7
+31 892955437 3 7
+31 892955437 4 7
+31 892955437 5 7
+31 1581497818 1 13
+31 1581497818 2 13
+31 1581497818 3 13
+31 1581497818 4 13
+31 1581497818 5 13
+31 2087270142 1 7
+31 2087270142 2 7
+31 2087270142 3 7
+31 2087270142 4 7
+31 2087270142 5 7
+31 1564424559 1 4
+31 1564424559 2 4
+31 1564424559 3 4
+31 1564424559 4 4
+31 1564424559 5 4
+31 1762953928 1 7
+31 1762953928 2 7
+31 1762953928 3 7
+31 1762953928 4 7
+31 1762953928 5 7
+31 264159138 1 14
+31 264159138 2 14
+31 264159138 3 14
+31 264159138 4 14
+31 264159138 5 14
+31 934393298 1 13
+31 934393298 2 13
+31 934393298 3 13
+31 934393298 4 13
+31 934393298 5 13
+31 425929304 1 8
+31 425929304 2 8
+31 425929304 3 8
+31 425929304 4 8
+31 425929304 5 8
+31 1431999721 1 9
+31 1431999721 2 9
+31 1431999721 3 9
+31 1431999721 4 9
+31 1431999721 5 9
+31 50432310 1 0
+31 50432310 2 0
+31 50432310 3 0
+31 50432310 4 0
+31 50432310 5 0
+31 671383138 1 0
+31 671383138 2 0
+31 671383138 3 0
+31 671383138 4 0
+31 671383138 5 0
+31 1514870594 1 15
+31 1514870594 2 15
+31 1514870594 3 15
+31 1514870594 4 15
+31 1514870594 5 15
+31 125594206 1 12
+31 125594206 2 12
+31 125594206 3 12
+31 125594206 4 12
+31 125594206 5 12
+31 340551370 1 4
+31 340551370 2 4
+31 340551370 3 4
+31 340551370 4 4
+31 340551370 5 4
+31 1623645007 1 15
+31 1623645007 2 15
+31 1623645007 3 15
+31 1623645007 4 15
+31 1623645007 5 15
+31 1348003716 1 4
+31 1348003716 2 4
+31 1348003716 3 4
+31 1348003716 4 4
+31 1348003716 5 4
+31 2037861051 1 7
+31 2037861051 2 7
+31 2037861051 3 7
+31 2037861051 4 7
+31 2037861051 5 7
+31 2057710326 1 5
+31 2057710326 2 5
+31 2057710326 3 5
+31 2057710326 4 5
+31 2057710326 5 5
+31 663428672 1 13
+31 663428672 2 13
+31 663428672 3 13
+31 663428672 4 13
+31 663428672 5 13
+31 1949076248 1 8
+31 1949076248 2 8
+31 1949076248 3 8
+31 1949076248 4 8
+31 1949076248 5 8
+31 1083205847 1 8
+31 1083205847 2 8
+31 1083205847 3 8
+31 1083205847 4 8
+31 1083205847 5 8
+31 1989744438 1 0
+31 1989744438 2 0
+31 1989744438 3 0
+31 1989744438 4 0
+31 1989744438 5 0
+31 815856732 1 9
+31 815856732 2 9
+31 815856732 3 9
+31 815856732 4 9
+31 815856732 5 9
+31 829877019 1 6
+31 829877019 2 6
+31 829877019 3 6
+31 829877019 4 6
+31 829877019 5 6
+31 188649293 1 10
+31 188649293 2 10
+31 188649293 3 10
+31 188649293 4 10
+31 188649293 5 10
+31 1198806123 1 1
+31 1198806123 2 1
+31 1198806123 3 1
+31 1198806123 4 1
+31 1198806123 5 1
+31 1973746385 1 4
+31 1973746385 2 4
+31 1973746385 3 4
+31 1973746385 4 4
+31 1973746385 5 4
+31 839543376 1 6
+31 839543376 2 6
+31 839543376 3 6
+31 839543376 4 6
+31 839543376 5 6
+31 1072944380 1 14
+31 1072944380 2 14
+31 1072944380 3 14
+31 1072944380 4 14
+31 1072944380 5 14
+31 1561590617 1 17
+31 1561590617 2 17
+31 1561590617 3 17
+31 1561590617 4 17
+31 1561590617 5 17
+31 551611217 1 10
+31 551611217 2 10
+31 551611217 3 10
+31 551611217 4 10
+31 551611217 5 10
+32 1036684082 1 9
+32 1036684082 2 9
+32 1036684082 3 9
+32 1036684082 4 9
+32 1036684082 5 9
+32 2486634245 1 10
+32 2486634245 2 10
+32 2486634245 3 10
+32 2486634245 4 10
+32 2486634245 5 10
+32 1960853583 1 14
+32 1960853583 2 14
+32 1960853583 3 14
+32 1960853583 4 14
+32 1960853583 5 14
+32 2216609468 1 3
+32 2216609468 2 3
+32 2216609468 3 3
+32 2216609468 4 3
+32 2216609468 5 3
+32 221178161 1 7
+32 221178161 2 7
+32 221178161 3 7
+32 221178161 4 7
+32 221178161 5 7
+32 439758692 1 3
+32 439758692 2 3
+32 439758692 3 3
+32 439758692 4 3
+32 439758692 5 3
+32 1129185496 1 12
+32 1129185496 2 12
+32 1129185496 3 12
+32 1129185496 4 12
+32 1129185496 5 12
+32 1867788184 1 4
+32 1867788184 2 4
+32 1867788184 3 4
+32 1867788184 4 4
+32 1867788184 5 4
+32 564853289 1 8
+32 564853289 2 8
+32 564853289 3 8
+32 564853289 4 8
+32 564853289 5 8
+32 2344179581 1 5
+32 2344179581 2 5
+32 2344179581 3 5
+32 2344179581 4 5
+32 2344179581 5 5
+32 2970472705 1 0
+32 2970472705 2 0
+32 2970472705 3 0
+32 2970472705 4 0
+32 2970472705 5 0
+32 4070187504 1 9
+32 4070187504 2 9
+32 4070187504 3 9
+32 4070187504 4 9
+32 4070187504 5 9
+32 2662144140 1 9
+32 2662144140 2 9
+32 2662144140 3 9
+32 2662144140 4 9
+32 2662144140 5 9
+32 4167572734 1 10
+32 4167572734 2 10
+32 4167572734 3 10
+32 4167572734 4 10
+32 4167572734 5 10
+32 927210200 1 6
+32 927210200 2 6
+32 927210200 3 6
+32 927210200 4 6
+32 927210200 5 6
+32 2208343448 1 5
+32 2208343448 2 5
+32 2208343448 3 5
+32 2208343448 4 5
+32 2208343448 5 5
+32 2192760228 1 3
+32 2192760228 2 3
+32 2192760228 3 3
+32 2192760228 4 3
+32 2192760228 5 3
+32 2166303367 1 7
+32 2166303367 2 7
+32 2166303367 3 7
+32 2166303367 4 7
+32 2166303367 5 7
+32 3688439934 1 6
+32 3688439934 2 6
+32 3688439934 3 6
+32 3688439934 4 6
+32 3688439934 5 6
+32 308030109 1 5
+32 308030109 2 5
+32 308030109 3 5
+32 308030109 4 5
+32 308030109 5 5
+32 1104848908 1 1
+32 1104848908 2 1
+32 1104848908 3 1
+32 1104848908 4 1
+32 1104848908 5 1
+32 3705758252 1 12
+32 3705758252 2 12
+32 3705758252 3 12
+32 3705758252 4 12
+32 3705758252 5 12
+32 336358057 1 2
+32 336358057 2 2
+32 336358057 3 2
+32 336358057 4 2
+32 336358057 5 2
+32 701422524 1 7
+32 701422524 2 7
+32 701422524 3 7
+32 701422524 4 7
+32 701422524 5 7
+32 95384115 1 9
+32 95384115 2 9
+32 95384115 3 9
+32 95384115 4 9
+32 95384115 5 9
+32 3922974711 1 14
+32 3922974711 2 14
+32 3922974711 3 14
+32 3922974711 4 14
+32 3922974711 5 14
+32 60262178 1 7
+32 60262178 2 7
+32 60262178 3 7
+32 60262178 4 7
+32 60262178 5 7
+32 2696528104 1 5
+32 2696528104 2 5
+32 2696528104 3 5
+32 2696528104 4 5
+32 2696528104 5 5
+32 19462365 1 15
+32 19462365 2 15
+32 19462365 3 15
+32 19462365 4 15
+32 19462365 5 15
+32 2463013988 1 12
+32 2463013988 2 12
+32 2463013988 3 12
+32 2463013988 4 12
+32 2463013988 5 12
+32 1023022920 1 3
+32 1023022920 2 3
+32 1023022920 3 3
+32 1023022920 4 3
+32 1023022920 5 3
+32 3781145032 1 13
+32 3781145032 2 13
+32 3781145032 3 13
+32 3781145032 4 13
+32 3781145032 5 13
+32 1830433185 1 10
+32 1830433185 2 10
+32 1830433185 3 10
+32 1830433185 4 10
+32 1830433185 5 10
+32 424433380 1 8
+32 424433380 2 8
+32 424433380 3 8
+32 424433380 4 8
+32 424433380 5 8
+32 1623797388 1 10
+32 1623797388 2 10
+32 1623797388 3 10
+32 1623797388 4 10
+32 1623797388 5 10
+32 3401848886 1 14
+32 3401848886 2 14
+32 3401848886 3 14
+32 3401848886 4 14
+32 3401848886 5 14
+32 1317540203 1 5
+32 1317540203 2 5
+32 1317540203 3 5
+32 1317540203 4 5
+32 1317540203 5 5
+32 1120055386 1 1
+32 1120055386 2 1
+32 1120055386 3 1
+32 1120055386 4 1
+32 1120055386 5 1
+32 454820083 1 0
+32 454820083 2 0
+32 454820083 3 0
+32 454820083 4 0
+32 454820083 5 0
+32 1359971009 1 14
+32 1359971009 2 14
+32 1359971009 3 14
+32 1359971009 4 14
+32 1359971009 5 14
+32 497197820 1 15
+32 497197820 2 15
+32 497197820 3 15
+32 497197820 4 15
+32 497197820 5 15
+32 4289564065 1 15
+32 4289564065 2 15
+32 4289564065 3 15
+32 4289564065 4 15
+32 4289564065 5 15
+32 124772759 1 17
+32 124772759 2 17
+32 124772759 3 17
+32 124772759 4 17
+32 124772759 5 17
+32 1308886828 1 1
+32 1308886828 2 1
+32 1308886828 3 1
+32 1308886828 4 1
+32 1308886828 5 1
+32 3243928933 1 10
+32 3243928933 2 10
+32 3243928933 3 10
+32 3243928933 4 10
+32 3243928933 5 10
+32 3788970499 1 1
+32 3788970499 2 1
+32 3788970499 3 1
+32 3788970499 4 1
+32 3788970499 5 1
+32 4103967014 1 0
+32 4103967014 2 0
+32 4103967014 3 0
+32 4103967014 4 0
+32 4103967014 5 0
+32 1705735405 1 10
+32 1705735405 2 10
+32 1705735405 3 10
+32 1705735405 4 10
+32 1705735405 5 10
+32 416033424 1 2
+32 416033424 2 2
+32 416033424 3 2
+32 416033424 4 2
+32 416033424 5 2
+32 514236867 1 4
+32 514236867 2 4
+32 514236867 3 4
+32 514236867 4 4
+32 514236867 5 4
+32 3686390881 1 4
+32 3686390881 2 4
+32 3686390881 3 4
+32 3686390881 4 4
+32 3686390881 5 4
+32 2125027247 1 12
+32 2125027247 2 12
+32 2125027247 3 12
+32 2125027247 4 12
+32 2125027247 5 12
+32 2029833655 1 8
+32 2029833655 2 8
+32 2029833655 3 8
+32 2029833655 4 8
+32 2029833655 5 8
+32 3917495445 1 7
+32 3917495445 2 7
+32 3917495445 3 7
+32 3917495445 4 7
+32 3917495445 5 7
+32 2650507935 1 5
+32 2650507935 2 5
+32 2650507935 3 5
+32 2650507935 4 5
+32 2650507935 5 5
+32 282773968 1 13
+32 282773968 2 13
+32 282773968 3 13
+32 282773968 4 13
+32 282773968 5 13
+32 446683627 1 10
+32 446683627 2 10
+32 446683627 3 10
+32 446683627 4 10
+32 446683627 5 10
+32 2843691041 1 15
+32 2843691041 2 15
+32 2843691041 3 15
+32 2843691041 4 15
+32 2843691041 5 15
+32 1191222343 1 8
+32 1191222343 2 8
+32 1191222343 3 8
+32 1191222343 4 8
+32 1191222343 5 8
+32 2016286435 1 10
+32 2016286435 2 10
+32 2016286435 3 10
+32 2016286435 4 10
+32 2016286435 5 10
+32 1893861518 1 5
+32 1893861518 2 5
+32 1893861518 3 5
+32 1893861518 4 5
+32 1893861518 5 5
+32 3977622147 1 12
+32 3977622147 2 12
+32 3977622147 3 12
+32 3977622147 4 12
+32 3977622147 5 12
+32 571267417 1 15
+32 571267417 2 15
+32 571267417 3 15
+32 571267417 4 15
+32 571267417 5 15
+32 2363239984 1 13
+32 2363239984 2 13
+32 2363239984 3 13
+32 2363239984 4 13
+32 2363239984 5 13
diff --git a/vdslib/src/tests/distribution/testdata/java_retired.state b/vdslib/src/tests/distribution/testdata/java_retired.state
new file mode 100644
index 00000000000..678f073e61b
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/java_retired.state
@@ -0,0 +1 @@
+distributor:20 storage:20 .3.r:2 .7.r:3 .12.r:5 \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/minimal-movement.java.results b/vdslib/src/tests/distribution/testdata/minimal-movement.java.results
new file mode 100644
index 00000000000..1db1a6c3eda
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/minimal-movement.java.results
@@ -0,0 +1,730 @@
+{
+ "cluster-state": "distributor:4 .2.s:d",
+ "distribution": "redundancy 3\ninitial_redundancy 0\nensure_primary_persisted true\nready_copies 0\nactive_per_leaf_group false\ndistributor_auto_ownership_transfer_on_whole_group_down true\ngroup[0].index \"invalid\"\ngroup[0].name \"invalid\"\ngroup[0].capacity 1.0\ngroup[0].partitions \"*\"\ngroup[0].nodes[0].index 0\ngroup[0].nodes[0].retired false\ngroup[0].nodes[1].index 1\ngroup[0].nodes[1].retired false\ngroup[0].nodes[2].index 2\ngroup[0].nodes[2].retired false\ngroup[0].nodes[3].index 3\ngroup[0].nodes[3].retired false\ngroup[0].nodes[4].index 4\ngroup[0].nodes[4].retired false\ngroup[0].nodes[5].index 5\ngroup[0].nodes[5].retired false\ngroup[0].nodes[6].index 6\ngroup[0].nodes[6].retired false\ngroup[0].nodes[7].index 7\ngroup[0].nodes[7].retired false\ngroup[0].nodes[8].index 8\ngroup[0].nodes[8].retired false\ngroup[0].nodes[9].index 9\ngroup[0].nodes[9].retired false\ndisk_distribution MODULO_BID",
+ "node-type": "distributor",
+ "redundancy": 3,
+ "node-count": 10,
+ "up-states": "uim",
+ "result": [
+ {
+ "bucket": "4000000000000000",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000002",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000003",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000004",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000005",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000006",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000007",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000008",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000009",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000a",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000b",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000c",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000d",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000010",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000011",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000012",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000000",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000002",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000003",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000004",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000005",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000006",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000007",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000008",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000009",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000000a",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000000b",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000000c",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000000d",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000000e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000010",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000011",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000012",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000000",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000002",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000003",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000004",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000005",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000006",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000007",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000008",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000009",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000000a",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000000b",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000000c",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000000d",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000000e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000010",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000011",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000012",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000001fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000001fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c0000000001fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "500000000009fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "540000000009fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "580000000009fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c0000000049fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "600000000049fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "640000000149fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "680000000349fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c0000000749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "700000000749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "740000001749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "780000003749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c0000003749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "80000000b749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "84000001b749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "88000003b749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8c000007b749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "9000000fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "9400001fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "9800003fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "9c00007fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "a000007fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "a400007fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "a800007fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "ac00047fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "b000047fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "b400147fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "b800347fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "bc00347fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c000b47fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c400b47fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c800b47fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "cc00b47fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "d000b47fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "d400b47fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "d800b47fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "dc00b47fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "e000b47fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "e400b47fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000098d2",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "44000000000098d2",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "48000000000298d2",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c000000000698d2",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "50000000000e98d2",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "54000000000e98d2",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "58000000002e98d2",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c000000002e98d2",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "60000000002e98d2",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "64000000012e98d2",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "68000000012e98d2",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c000000052e98d2",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "70000000052e98d2",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "74000000152e98d2",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "78000000152e98d2",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c000000152e98d2",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "80000000952e98d2",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "84000001952e98d2",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "88000001952e98d2",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8c000001952e98d2",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "90000001952e98d2",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "94000001952e98d2",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "98000001952e98d2",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "9c000041952e98d2",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "a00000c1952e98d2",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "a40000c1952e98d2",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "a80002c1952e98d2",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "ac0002c1952e98d2",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "b00002c1952e98d2",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "b40012c1952e98d2",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "b80012c1952e98d2",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "bc0012c1952e98d2",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00092c1952e98d2",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c40192c1952e98d2",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c80192c1952e98d2",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "cc0192c1952e98d2",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "d00992c1952e98d2",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "d41992c1952e98d2",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "d83992c1952e98d2",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "dc7992c1952e98d2",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "e07992c1952e98d2",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "e47992c1952e98d2",
+ "nodes": [3],
+ "failure": "NONE"
+ }
+ ]
+} \ No newline at end of file
diff --git a/vdslib/src/tests/distribution/testdata/simple.java.results b/vdslib/src/tests/distribution/testdata/simple.java.results
new file mode 100644
index 00000000000..8b23785fdcd
--- /dev/null
+++ b/vdslib/src/tests/distribution/testdata/simple.java.results
@@ -0,0 +1,730 @@
+{
+ "cluster-state": "distributor:10",
+ "distribution": "redundancy 3\ninitial_redundancy 0\nensure_primary_persisted true\nready_copies 0\nactive_per_leaf_group false\ndistributor_auto_ownership_transfer_on_whole_group_down true\ngroup[0].index \"invalid\"\ngroup[0].name \"invalid\"\ngroup[0].capacity 1.0\ngroup[0].partitions \"*\"\ngroup[0].nodes[0].index 0\ngroup[0].nodes[0].retired false\ngroup[0].nodes[1].index 1\ngroup[0].nodes[1].retired false\ngroup[0].nodes[2].index 2\ngroup[0].nodes[2].retired false\ngroup[0].nodes[3].index 3\ngroup[0].nodes[3].retired false\ngroup[0].nodes[4].index 4\ngroup[0].nodes[4].retired false\ngroup[0].nodes[5].index 5\ngroup[0].nodes[5].retired false\ngroup[0].nodes[6].index 6\ngroup[0].nodes[6].retired false\ngroup[0].nodes[7].index 7\ngroup[0].nodes[7].retired false\ngroup[0].nodes[8].index 8\ngroup[0].nodes[8].retired false\ngroup[0].nodes[9].index 9\ngroup[0].nodes[9].retired false\ndisk_distribution MODULO_BID",
+ "node-type": "distributor",
+ "redundancy": 3,
+ "node-count": 10,
+ "up-states": "uim",
+ "result": [
+ {
+ "bucket": "4000000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000008",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000009",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000010",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000011",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000012",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4000000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000008",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000009",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000000a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000000b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000000c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000000d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000000e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000010",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000011",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000012",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4400000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000000",
+ "nodes": [6],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000001",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000002",
+ "nodes": [4],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000003",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000004",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000005",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000006",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000007",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000008",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000009",
+ "nodes": [3],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000000a",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000000b",
+ "nodes": [8],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000000c",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000000d",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000000e",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000000000f",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000010",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000011",
+ "nodes": [7],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000012",
+ "nodes": [5],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4800000000000013",
+ "nodes": [1],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "400000000000fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "440000000001fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "480000000001fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c0000000001fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "500000000009fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "540000000009fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "580000000009fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c0000000049fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "600000000049fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "640000000149fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "680000000349fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c0000000749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "700000000749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "740000001749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "780000003749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c0000003749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "80000000b749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "84000001b749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "88000003b749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8c000007b749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "9000000fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "9400001fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "9800003fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "9c00007fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "a000007fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "a400007fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "a800007fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "ac00047fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "b000047fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "b400147fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "b800347fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "bc00347fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c000b47fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c400b47fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c800b47fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "cc00b47fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "d000b47fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "d400b47fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "d800b47fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "dc00b47fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "e000b47fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "e400b47fb749fe68",
+ "nodes": [0],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "40000000000098d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "44000000000098d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "48000000000298d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "4c000000000698d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "50000000000e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "54000000000e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "58000000002e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "5c000000002e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "60000000002e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "64000000012e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "68000000012e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "6c000000052e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "70000000052e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "74000000152e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "78000000152e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "7c000000152e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "80000000952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "84000001952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "88000001952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "8c000001952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "90000001952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "94000001952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "98000001952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "9c000041952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "a00000c1952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "a40000c1952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "a80002c1952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "ac0002c1952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "b00002c1952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "b40012c1952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "b80012c1952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "bc0012c1952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c00092c1952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c40192c1952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "c80192c1952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "cc0192c1952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "d00992c1952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "d41992c1952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "d83992c1952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "dc7992c1952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "e07992c1952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ },
+ {
+ "bucket": "e47992c1952e98d2",
+ "nodes": [2],
+ "failure": "NONE"
+ }
+ ]
+} \ No newline at end of file
diff --git a/vdslib/src/tests/state/.gitignore b/vdslib/src/tests/state/.gitignore
new file mode 100644
index 00000000000..333f254ba10
--- /dev/null
+++ b/vdslib/src/tests/state/.gitignore
@@ -0,0 +1,8 @@
+*.So
+*.lo
+.*.swp
+.depend
+.depend.NEW
+.deps
+.libs
+Makefile
diff --git a/vdslib/src/tests/state/CMakeLists.txt b/vdslib/src/tests/state/CMakeLists.txt
new file mode 100644
index 00000000000..fead8cd022b
--- /dev/null
+++ b/vdslib/src/tests/state/CMakeLists.txt
@@ -0,0 +1,7 @@
+# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_library(vdslib_teststate
+ SOURCES
+ clusterstatetest.cpp
+ nodestatetest.cpp
+ DEPENDS
+)
diff --git a/vdslib/src/tests/state/clusterstatetest.cpp b/vdslib/src/tests/state/clusterstatetest.cpp
new file mode 100644
index 00000000000..c2abfef8403
--- /dev/null
+++ b/vdslib/src/tests/state/clusterstatetest.cpp
@@ -0,0 +1,389 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#include <vespa/fastos/fastos.h>
+#include <vespa/vdslib/state/clusterstate.h>
+
+#include <list>
+#include <vespa/document/bucket/bucketidfactory.h>
+#include <cmath>
+#include <vespa/vdslib/state/random.h>
+#include <vespa/vdstestlib/cppunit/macros.h>
+
+using vespalib::string;
+
+namespace storage {
+namespace lib {
+
+struct ClusterStateTest : public CppUnit::TestFixture {
+
+ void testBasicFunctionality();
+ void testErrorBehaviour();
+ void testBackwardsCompability();
+ void testDetailed();
+ void testParseFailure();
+ void testParseFailureGroups();
+
+ void testDiff();
+
+ CPPUNIT_TEST_SUITE(ClusterStateTest);
+ CPPUNIT_TEST(testBasicFunctionality);
+ CPPUNIT_TEST(testErrorBehaviour);
+ CPPUNIT_TEST(testBackwardsCompability);
+ CPPUNIT_TEST(testDetailed);
+
+ // Ideal state tests.
+ CPPUNIT_TEST(testParseFailure);
+ CPPUNIT_TEST(testParseFailureGroups);
+ CPPUNIT_TEST(testDiff);
+ CPPUNIT_TEST_SUITE_END();
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(ClusterStateTest);
+
+void
+ClusterStateTest::testDiff() {
+ ClusterState state1("distributor:9 storage:4");
+ ClusterState state2("distributor:7 storage:6");
+ ClusterState state3("distributor:9 storage:2");
+ CPPUNIT_ASSERT_EQUAL(
+ std::string("storage [4: d to u, 5: d to u] "
+ "distributor [7: u to d, 8: u to d]"),
+ state1.getTextualDifference(state2));
+ CPPUNIT_ASSERT_EQUAL(
+ std::string("storage [2: u to d, 3: u to d, 4: u to d, 5: u to d] "
+ "distributor [7: d to u, 8: d to u]"),
+ state2.getTextualDifference(state3));
+}
+
+
+#define VERIFY3(source, result, type, typestr) { \
+ vespalib::asciistream ost; \
+ try{ \
+ state->serialize(ost, type); \
+ } catch (std::exception& e) { \
+ CPPUNIT_FAIL("Failed to serialize system state " \
+ + state->toString(true) + " in " + std::string(typestr) \
+ + " format: " + std::string(e.what())); \
+ } \
+ CPPUNIT_ASSERT_EQUAL_MSG(vespalib::string(state->toString(true)), \
+ vespalib::string(typestr) + " \"" + vespalib::string(result) + "\"", \
+ vespalib::string(typestr) + " \"" + ost.str() + "\""); \
+}
+
+#define VERIFY2(serialized, result, testOld, testNew) { \
+ std::unique_ptr<ClusterState> state; \
+ try{ \
+ state.reset(new ClusterState(serialized)); \
+ } catch (std::exception& e) { \
+ CPPUNIT_FAIL("Failed to parse '" + std::string(serialized) \
+ + "': " + e.what()); \
+ } \
+ if (testOld) VERIFY3(serialized, result, true, "Old") \
+ if (testNew) VERIFY3(serialized, result, false, "New") \
+}
+
+#define VERIFYSAMEOLD(serialized) VERIFY2(serialized, serialized, true, false)
+#define VERIFYOLD(serialized, result) VERIFY2(serialized, result, true, false)
+#define VERIFYSAMENEW(serialized) VERIFY2(serialized, serialized, false, true)
+#define VERIFYNEW(serialized, result) VERIFY2(serialized, result, false, true)
+#define VERIFYSAME(serialized) VERIFY2(serialized, serialized, true, true)
+#define VERIFY(serialized, result) VERIFY2(serialized, result, true, true)
+
+#define VERIFY_FAIL(serialized, error) { \
+ try{ \
+ ClusterState state(serialized); \
+ CPPUNIT_FAIL("Parsing the state '" + std::string(serialized) \
+ + "' is supposed to fail."); \
+ } catch (vespalib::Exception& e) { \
+ CPPUNIT_ASSERT_MATCH_REGEX(error, e.getMessage()); \
+ } \
+}
+
+void
+ClusterStateTest::testBasicFunctionality()
+{
+ // Version is default and should not be written
+ VERIFYNEW("version:0", "");
+ VERIFYNEW("version:1", "version:1");
+
+ // Cluster state up is default and should not be written
+ VERIFYNEW("cluster:u", "");
+ VERIFYSAMENEW("cluster:d");
+ VERIFYSAMENEW("cluster:i");
+ VERIFYSAMENEW("cluster:s");
+
+ // No need to write node counts if no nodes exist.
+ VERIFYNEW("cluster:d distributor:0 storage:0", "cluster:d");
+
+ // Test legal distributor states
+ VERIFYNEW("distributor:10 .1.s:i .2.s:u .3.s:s .4.s:d",
+ "distributor:10 .1.s:i .1.i:0 .3.s:s .4.s:d");
+
+ // Test legal storage states
+ VERIFYNEW("storage:10 .1.s:i .2.s:u .3.s:d .4.s:m .5.s:r",
+ "storage:10 .1.s:i .1.i:0 .3.s:d .4.s:m .5.s:r");
+
+ // Test legal disk states
+ VERIFYNEW("storage:10 .1.d:4 .1.d.0.s:u .1.d.1.s:d",
+ "storage:10 .1.d:4 .1.d.1.s:d");
+
+ // Test other disk properties
+ VERIFYSAMENEW("storage:10 .1.d:4 .1.d.0.c:1.4");
+
+ // Test other distributor node propertise
+ // (Messages is excluded from system states to not make them too long as
+ // most nodes have no use for them)
+ VERIFYNEW("distributor:9 .7.m:foo\\x20bar", "distributor:9");
+ VERIFYSAMENEW("distributor:4 .2.s:m");
+
+ // Test other storage node propertise
+ // (Messages is excluded from system states to not make them too long as
+ // most nodes have no use for them)
+ VERIFYNEW("storage:9 .3.c:2.3 .4.r:8 .7.m:foo\\x20bar",
+ "storage:9 .3.c:2.3 .4.r:8");
+
+ // Test that messages are kept in verbose mode, even if last index
+ {
+ ClusterState state("storage:5 .4.s:d .4.m:Foo\\x20bar");
+ const NodeState& ns(state.getNodeState(Node(NodeType::STORAGE, 4)));
+ CPPUNIT_ASSERT_EQUAL(string("Foo bar"), ns.getDescription());
+ }
+
+ ClusterState state;
+ state.setClusterState(State::UP);
+ state.setNodeState(Node(NodeType::DISTRIBUTOR, 3),
+ NodeState(NodeType::DISTRIBUTOR, State::UP));
+ CPPUNIT_ASSERT_EQUAL(std::string("distributor:4 .0.s:d .1.s:d .2.s:d"),
+ state.toString(false));
+ state.setNodeState(Node(NodeType::DISTRIBUTOR, 1),
+ NodeState(NodeType::DISTRIBUTOR, State::UP));
+ CPPUNIT_ASSERT_EQUAL(std::string("distributor:4 .0.s:d .2.s:d"),
+ state.toString(false));
+ state.setNodeState(Node(NodeType::DISTRIBUTOR, 3),
+ NodeState(NodeType::DISTRIBUTOR, State::DOWN));
+ CPPUNIT_ASSERT_EQUAL(std::string("distributor:2 .0.s:d"),
+ state.toString(false));
+ state.setNodeState(Node(NodeType::DISTRIBUTOR, 4),
+ NodeState(NodeType::DISTRIBUTOR, State::UP));
+ CPPUNIT_ASSERT_EQUAL(std::string("distributor:5 .0.s:d .2.s:d .3.s:d"),
+ state.toString(false));
+}
+
+void
+ClusterStateTest::testErrorBehaviour()
+{
+ // Keys with invalid values
+
+ // Index out of range
+ VERIFY_FAIL("storage:5 distributor:4 .4.s:s",
+ "Cannot index distributor node 4 of 4");
+ VERIFY_FAIL("distributor:5 storage:4 .4.s:s",
+ "Cannot index storage node 4 of 4");
+
+ // Test illegal cluster states
+ VERIFY_FAIL("cluster:m", "Maintenance is not a legal cluster state");
+ VERIFY_FAIL("cluster:r", "Retired is not a legal cluster state");
+
+ // Test illegal distributor states
+// Currently set to legal
+// VERIFY_FAIL("distributor:4 .2.s:r",
+// "Retired is not a legal distributor state");
+
+ // Test illegal storage states
+ VERIFY_FAIL("storage:4 .2.d:2 .2.d.5.s:d", "Cannot index disk 5 of 2");
+
+ // Test blatantly illegal values for known attributes:
+ VERIFY_FAIL("distributor:4 .2.s:z", "Unknown state z given.*");
+ VERIFY_FAIL("distributor:4 .2.i:foobar",
+ ".*Init progress must be a floating point number from .*");
+ VERIFY_FAIL("storage:4 .2.d:foobar", "Invalid disk count 'foobar'. Need.*");
+ VERIFY_FAIL("storage:4 .2.d:2 .2.d.1.s:foobar",
+ "Unknown state foobar given.*");
+ VERIFY_FAIL("storage:4 .2.d:2 .2.d.1.c:foobar",
+ "Illegal disk capacity 'foobar'. Capacity must be a .*");
+ VERIFY_FAIL("storage:4 .2.d:2 .2.d.a.s:d",
+ "Invalid disk index 'a'. Need a positive integer .*");
+
+ // Lacking absolute path first
+ VERIFY_FAIL(".2.s:d distributor:4", "The first path in system state.*");
+
+ // Unknown tokens
+ VERIFYNEW("distributor:4 .2.d:2", "distributor:4");
+ VERIFYNEW("distributor:4 .2.d:2 .2.d:2", "distributor:4");
+ VERIFYNEW("distributor:4 .2.c:1.2 .3.r:2.0", "distributor:4");
+ VERIFYNEW("distributor:4 .2:foo storage:5 .4:d", "distributor:4 storage:5");
+ VERIFYNEW("ballalaika:true distributor:4 .2.urk:oj .2.z:foo .2.s:s "
+ ".2.j:foo storage:10 .3.d:4 .3.d.2.a:boo .3.s:s",
+ "distributor:4 .2.s:s storage:10 .3.s:s .3.d:4");
+}
+
+void
+ClusterStateTest::testBackwardsCompability()
+{
+ // 4.1 and older nodes do not support some features, and the java parser
+ // do not allow unknown elements as it was supposed to do, thus we should
+ // avoid using new features when talking to 4.1 nodes.
+
+ // - 4.1 nodes should not see new cluster, version, initializing and
+ // description tags.
+ VERIFYOLD("version:4 cluster:i storage:2 .0.s:i .0.i:0.5 .1.m:foobar",
+ "distributor:0 storage:2 .0.s:i");
+
+ // - 4.1 nodes have only one disk property being state, so in 4.1, a
+ // disk state is typically set as .4.d.2:d while in new format it
+ // specifies that this is the state .4.d.2.s:d
+ VERIFYSAMEOLD("distributor:0 storage:3 .2.d:10 .2.d.4:d");
+ VERIFYOLD("distributor:0 storage:3 .2.d:10 .2.d.4.s:d",
+ "distributor:0 storage:3 .2.d:10 .2.d.4:d");
+
+ // - 4.1 nodes should always have distributor and storage tags with counts.
+ VERIFYOLD("storage:4", "distributor:0 storage:4");
+ VERIFYOLD("distributor:4", "distributor:4 storage:0");
+
+ // - 4.1 nodes should not see the state stopping
+ VERIFYOLD("storage:4 .2.s:s", "distributor:0 storage:4 .2.s:d");
+
+}
+
+void
+ClusterStateTest::testDetailed()
+{
+ ClusterState state(
+ "version:314 cluster:i "
+ "distributor:8 .1.s:i .3.s:i .3.i:0.5 .5.s:d .7.m:foo\\x20bar "
+ "storage:10 .2.d:16 .2.d.3:d .4.s:d .5.c:1.3 .5.r:4"
+ " .6.m:bar\\tfoo .7.s:m .8.d:10 .8.d.4.c:0.6 .8.d.4.m:small"
+ );
+ CPPUNIT_ASSERT_EQUAL(314u, state.getVersion());
+ CPPUNIT_ASSERT_EQUAL(State::INITIALIZING, state.getClusterState());
+ CPPUNIT_ASSERT_EQUAL(uint16_t(8),state.getNodeCount(NodeType::DISTRIBUTOR));
+ CPPUNIT_ASSERT_EQUAL(uint16_t(10),state.getNodeCount(NodeType::STORAGE));
+
+ // Testing distributor node states
+ for (uint16_t i = 0; i <= 20; ++i) {
+ const NodeState& ns(state.getNodeState(Node(NodeType::DISTRIBUTOR, i)));
+ // Test node states
+ if (i == 1 || i == 3) {
+ CPPUNIT_ASSERT_EQUAL(State::INITIALIZING, ns.getState());
+ } else if (i == 5 || i >= 8) {
+ CPPUNIT_ASSERT_EQUAL(State::DOWN, ns.getState());
+ } else {
+ CPPUNIT_ASSERT_EQUAL(State::UP, ns.getState());
+ }
+ // Test initialize progress
+ if (i == 1) {
+ CPPUNIT_ASSERT_EQUAL(vespalib::Double(0.0), ns.getInitProgress());
+ } else if (i == 3) {
+ CPPUNIT_ASSERT_EQUAL(vespalib::Double(0.5), ns.getInitProgress());
+ } else {
+ CPPUNIT_ASSERT_EQUAL(vespalib::Double(0.0), ns.getInitProgress());
+ }
+ // Test message
+ if (i == 7) {
+ CPPUNIT_ASSERT_EQUAL(string("foo bar"), ns.getDescription());
+ } else {
+ CPPUNIT_ASSERT_EQUAL(string(""), ns.getDescription());
+ }
+ }
+
+ // Testing storage node states
+ for (uint16_t i = 0; i <= 20; ++i) {
+ const NodeState& ns(state.getNodeState(Node(NodeType::STORAGE, i)));
+ // Test node states
+ if (i == 4 || i >= 10) {
+ CPPUNIT_ASSERT_EQUAL(State::DOWN, ns.getState());
+ } else if (i == 7) {
+ CPPUNIT_ASSERT_EQUAL(State::MAINTENANCE, ns.getState());
+ } else {
+ CPPUNIT_ASSERT_EQUAL(State::UP, ns.getState());
+ }
+ // Test disk states
+ if (i == 2) {
+ CPPUNIT_ASSERT_EQUAL(uint16_t(16), ns.getDiskCount());
+ } else if (i == 8) {
+ CPPUNIT_ASSERT_EQUAL(uint16_t(10), ns.getDiskCount());
+ } else {
+ CPPUNIT_ASSERT_EQUAL(uint16_t(0), ns.getDiskCount());
+ }
+ if (i == 2) {
+ for (uint16_t j = 0; j < 16; ++j) {
+ if (j == 3) {
+ CPPUNIT_ASSERT_EQUAL(State::DOWN,
+ ns.getDiskState(j).getState());
+ } else {
+ CPPUNIT_ASSERT_EQUAL(State::UP,
+ ns.getDiskState(j).getState());
+ }
+ }
+ } else if (i == 8) {
+ for (uint16_t j = 0; j < 10; ++j) {
+ if (j == 4) {
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(
+ 0.6, ns.getDiskState(j).getCapacity().getValue(), 0.0001);
+ CPPUNIT_ASSERT_EQUAL(
+ string("small"),
+ ns.getDiskState(j).getDescription());
+ } else {
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(
+ 1.0, ns.getDiskState(j).getCapacity().getValue(), 0.0001);
+ CPPUNIT_ASSERT_EQUAL(
+ string(""),
+ ns.getDiskState(j).getDescription());
+ }
+ }
+ }
+ // Test message
+ if (i == 6) {
+ CPPUNIT_ASSERT_EQUAL(string("bar\tfoo"), ns.getDescription());
+ } else {
+ CPPUNIT_ASSERT_EQUAL(string(""), ns.getDescription());
+ }
+ // Test reliability
+ if (i == 5) {
+ CPPUNIT_ASSERT_EQUAL(uint16_t(4), ns.getReliability());
+ } else {
+ CPPUNIT_ASSERT_EQUAL(uint16_t(1), ns.getReliability());
+ }
+ // Test capacity
+ if (i == 5) {
+ CPPUNIT_ASSERT_EQUAL(vespalib::Double(1.3), ns.getCapacity());
+ } else {
+ CPPUNIT_ASSERT_EQUAL(vespalib::Double(1.0), ns.getCapacity());
+ }
+ }
+
+}
+
+void
+ClusterStateTest::testParseFailure()
+{
+ try {
+ ClusterState state("storage");
+ CPPUNIT_ASSERT(false);
+ } catch (vespalib::Exception& e) {
+ }
+
+ try {
+ ClusterState state("");
+ } catch (vespalib::Exception& e) {
+ CPPUNIT_ASSERT(false);
+ }
+
+ try {
+ ClusterState state(".her:tull");
+ CPPUNIT_ASSERT(false);
+ } catch (vespalib::Exception& e) {
+ }
+}
+
+void
+ClusterStateTest::testParseFailureGroups()
+{
+ try {
+ ClusterState state(")");
+ CPPUNIT_ASSERT(false);
+ } catch (vespalib::Exception& e) {
+ }
+}
+
+} // lib
+} // storage
diff --git a/vdslib/src/tests/state/generate_plots.sh b/vdslib/src/tests/state/generate_plots.sh
new file mode 100755
index 00000000000..975d7b513e2
--- /dev/null
+++ b/vdslib/src/tests/state/generate_plots.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+yum ls gnuplot &> /dev/null
+
+if [ $? -ne 0 ]; then
+ echo "gnuplot is not installed. Please do: sudo yum install gnuplot"
+fi
+
+echo "cp data files to tests/state/plots/data"
+cp datadistribution_*.dat state/plots/data/ &> /dev/null
+
+echo "ploting graphs"
+for a in `ls state/plots/scripts`; do echo "$a"; gnuplot state/plots/scripts/$a; done
+
+echo "mv png files to graphs directory"
+mv *.png state/plots/graphs/ &> /dev/null
diff --git a/vdslib/src/tests/state/grouptest.cpp b/vdslib/src/tests/state/grouptest.cpp
new file mode 100644
index 00000000000..c61f1e37bb9
--- /dev/null
+++ b/vdslib/src/tests/state/grouptest.cpp
@@ -0,0 +1,381 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#include <vespa/fastos/fastos.h>
+#include <boost/lexical_cast.hpp>
+#include <cppunit/extensions/HelperMacros.h>
+#include <vespa/vdslib/state/nodetype.h>
+#include <vdslib/state/group.h>
+#include <vespa/vdslib/state/idealgroup.h>
+#include <vespa/vespalib/util/exceptions.h>
+#include <iostream>
+#include <algorithm>
+
+using namespace std;
+using namespace vdslib;
+
+class GroupTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(GroupTest);
+ CPPUNIT_TEST(testTree);
+ CPPUNIT_TEST(testSetNodes);
+ CPPUNIT_TEST(testOperators);
+ CPPUNIT_TEST(testStarConversion);
+ CPPUNIT_TEST(testGroupIndexOrder);
+ CPPUNIT_TEST(testNodeIndexOrder);
+ CPPUNIT_TEST(testIdealGroupRedundancyOrder);
+ CPPUNIT_TEST(testIdealGroupScoreOrder);
+ CPPUNIT_TEST(testIdealGroupPickingConsistency);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+protected:
+ void testTree();
+ void testSetNodes();
+ void testOperators();
+ void testStarConversion();
+ void testGroupIndexOrder();
+ void testNodeIndexOrder();
+ void testIdealGroupRedundancyOrder();
+ void testIdealGroupScoreOrder();
+ void testIdealGroupPickingConsistency();
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION( GroupTest );
+
+#define MAKEGROUP(group, name, index, distribution) \
+ Group group; \
+ group.setName(name); \
+ group.setIndex(index); \
+ group.setDistribution(distribution);
+
+#define MAKEGROUPPTR(group, name, index, distribution) \
+ Group* group = new Group(); \
+ group->setName(name); \
+ group->setIndex(index); \
+ group->setDistribution(distribution);
+
+#define VERIFY(group, expected) { \
+ std::ostringstream ost; \
+ group.serialize(ost, true); \
+ CPPUNIT_ASSERT_EQUAL(std::string(expected), ost.str()); \
+}
+
+void
+GroupTest::testTree()
+{
+ uint16_t numGroups=10;
+
+ std::vector<Group*> groups;
+ for (uint16_t i=0; i< numGroups; ++i){
+ std::string name = vespalib::make_string("groupname%d", i);
+ MAKEGROUPPTR(g, name, i, "");
+ if (i >= numGroups/2) {
+ std::string storageIndexes =
+ vespalib::make_string("[%d-%d]", i, i);
+ g->setNodes(NodeType::STORAGE, storageIndexes);
+ std::string distributorIndexes =
+ vespalib::make_string("[%d-%d]", i-1, i-1);
+ g->setNodes(NodeType::DISTRIBUTOR, distributorIndexes);
+ }
+ groups.push_back(g);
+ }
+
+ for (uint16_t i=numGroups-1; i>0; --i){
+ uint16_t child = i;
+ uint16_t parent = i/2;
+ groups[child]->setParent(groups[parent]);
+ groups[parent]->addSubGroup(groups[child]);
+ }
+
+ //groups[0]->print(std::cerr, true, ""); std::cerr << "\n";
+
+ CPPUNIT_ASSERT_EQUAL((uint16_t)(numGroups-1),
+ groups[0]->getMaxIndex(NodeType::STORAGE));
+ CPPUNIT_ASSERT_EQUAL((uint16_t)(numGroups-2),
+ groups[0]->getMaxIndex(NodeType::DISTRIBUTOR));
+
+ for (uint16_t i=0; i<numGroups+1; ++i){
+ if (i<numGroups/2 || i>=numGroups) {
+ CPPUNIT_ASSERT(!groups[0]->containsNode(NodeType::STORAGE, i));
+ } else {
+ CPPUNIT_ASSERT(groups[0]->containsNode(NodeType::STORAGE, i));
+ }
+ }
+
+ delete groups[0];
+}
+
+void
+GroupTest::testSetNodes()
+{
+ MAKEGROUP(group, "group", 0, "");
+ std::string noNodes(" ( name:group index:0 )");
+ std::string threeNodes(" ( name:group index:0 distributor:[0-2] )");
+ {
+ try {
+ group.setNodes(NodeType::DISTRIBUTOR, "a");
+ CPPUNIT_ASSERT(false);
+ } catch (boost::bad_lexical_cast& e) {
+ VERIFY(group, noNodes);
+ }
+ try {
+ group.setNodes(NodeType::DISTRIBUTOR, "[b]");
+ CPPUNIT_ASSERT(false);
+ } catch (boost::bad_lexical_cast& e) {
+ VERIFY(group, noNodes);
+ }
+ try {
+ group.setNodes(NodeType::DISTRIBUTOR, "[0-c]");
+ CPPUNIT_ASSERT(false);
+ } catch (boost::bad_lexical_cast& e) {
+ VERIFY(group, noNodes);
+ }
+ try {
+ group.setNodes(NodeType::DISTRIBUTOR, "[-1-6]");
+ CPPUNIT_ASSERT(false);
+ } catch (boost::bad_lexical_cast& e) {
+ VERIFY(group, noNodes);
+ }
+ group.setNodes(NodeType::DISTRIBUTOR, "[5-3]");
+ //group.print(std::cerr, true, ""); std::cerr << "\n";
+ VERIFY(group, noNodes);
+
+ group.setNodes(NodeType::DISTRIBUTOR, "3");
+ VERIFY(group, threeNodes);
+
+ group.setNodes(NodeType::DISTRIBUTOR, "[0-2]");
+ VERIFY(group, threeNodes);
+
+ group.setNodes(NodeType::DISTRIBUTOR, "[0,1,2]");
+ VERIFY(group, threeNodes);
+
+ group.setNodes(NodeType::DISTRIBUTOR, "[,0,1,2,]");
+ VERIFY(group, threeNodes);
+
+ group.setNodes(NodeType::DISTRIBUTOR, "[0,0-2]");
+ VERIFY(group, threeNodes);
+ }
+}
+
+void
+GroupTest::testOperators()
+{
+ {
+ MAKEGROUP(g0, "group", 0, "1|*|*");
+ MAKEGROUP(g1, "group", 1, "1|*|*");
+ CPPUNIT_ASSERT(g0 != g1);
+ }
+ {
+ MAKEGROUP(g0, "group", 0, "1|*");
+ MAKEGROUP(g1, "group", 0, "1|*|*");
+ CPPUNIT_ASSERT(g0 != g1);
+ }
+ {
+ MAKEGROUPPTR(g0, "group", 0, "1|*");
+ MAKEGROUPPTR(g1, "group", 1, "1|*|*");
+ g0->addSubGroup(g1);
+ MAKEGROUPPTR(g2, "group", 0, "1|*");
+ CPPUNIT_ASSERT(g0 != g2);
+ delete g0; delete g2;
+ }
+}
+
+
+void
+GroupTest::testStarConversion()
+{
+ {
+ MAKEGROUP(g, "group", 0, "1|*|*");
+ std::vector<double> distribution = g.getDistribution(5);
+ CPPUNIT_ASSERT_EQUAL((size_t) 3, distribution.size());
+ CPPUNIT_ASSERT_EQUAL((double) 1, distribution[0]);
+ CPPUNIT_ASSERT_EQUAL((double) 2, distribution[1]);
+ CPPUNIT_ASSERT_EQUAL((double) 2, distribution[2]);
+ }
+ {
+ MAKEGROUP(g, "group", 0, "1|*|*");
+ std::vector<double> distribution = g.getDistribution(3);
+ CPPUNIT_ASSERT_EQUAL((size_t) 3, distribution.size());
+ CPPUNIT_ASSERT_EQUAL((double) 1, distribution[0]);
+ CPPUNIT_ASSERT_EQUAL((double) 1, distribution[1]);
+ CPPUNIT_ASSERT_EQUAL((double) 1, distribution[2]);
+ }
+ {
+ MAKEGROUP(g, "group", 0, "1|*");
+ std::vector<double> distribution = g.getDistribution(3);
+ CPPUNIT_ASSERT_EQUAL((size_t) 2, distribution.size());
+ CPPUNIT_ASSERT_EQUAL((double) 1, distribution[0]);
+ CPPUNIT_ASSERT_EQUAL((double) 2, distribution[1]);
+ }
+ {
+ MAKEGROUP(g, "group", 0, "4|*");
+ std::vector<double> distribution = g.getDistribution(3);
+ CPPUNIT_ASSERT_EQUAL((size_t) 1, distribution.size());
+ CPPUNIT_ASSERT_EQUAL((double) 3, distribution[0]);
+ }
+ {
+ MAKEGROUP(g, "group", 0, "2|*");
+ std::vector<double> distribution = g.getDistribution(3);
+ CPPUNIT_ASSERT_EQUAL((size_t) 2, distribution.size());
+ CPPUNIT_ASSERT_EQUAL((double) 2, distribution[0]);
+ CPPUNIT_ASSERT_EQUAL((double) 1, distribution[1]);
+ }
+ {
+ MAKEGROUP(g, "group", 0, "2|*");
+ std::vector<double> distribution = g.getDistribution(0);
+ CPPUNIT_ASSERT_EQUAL((size_t) 0, distribution.size());
+ }
+ {
+ MAKEGROUP(g, "group", 0, "*|*");
+ std::vector<double> distribution = g.getDistribution(3);
+ CPPUNIT_ASSERT_EQUAL((size_t) 2, distribution.size());
+ CPPUNIT_ASSERT_EQUAL((double) 2, distribution[0]);
+ CPPUNIT_ASSERT_EQUAL((double) 1, distribution[1]);
+ }
+ {
+ MAKEGROUP(g, "group", 0, "*|*|*");
+ std::vector<double> distribution = g.getDistribution(4);
+ CPPUNIT_ASSERT_EQUAL((size_t) 3, distribution.size());
+ CPPUNIT_ASSERT_EQUAL((double) 2, distribution[0]);
+ CPPUNIT_ASSERT_EQUAL((double) 1, distribution[1]);
+ CPPUNIT_ASSERT_EQUAL((double) 1, distribution[2]);
+ }
+ {
+ MAKEGROUP(g, "group", 0, "*|*|*");
+ std::vector<double> distribution = g.getDistribution(5);
+ CPPUNIT_ASSERT_EQUAL((size_t) 3, distribution.size());
+ CPPUNIT_ASSERT_EQUAL((double) 2, distribution[0]);
+ CPPUNIT_ASSERT_EQUAL((double) 2, distribution[1]);
+ CPPUNIT_ASSERT_EQUAL((double) 1, distribution[2]);
+ }
+ {
+ MAKEGROUP(g, "group", 0, "*|*|*|*");
+ std::vector<double> distribution = g.getDistribution(5);
+ CPPUNIT_ASSERT_EQUAL((size_t) 4, distribution.size());
+ CPPUNIT_ASSERT_EQUAL((double) 2, distribution[0]);
+ CPPUNIT_ASSERT_EQUAL((double) 1, distribution[1]);
+ CPPUNIT_ASSERT_EQUAL((double) 1, distribution[2]);
+ CPPUNIT_ASSERT_EQUAL((double) 1, distribution[3]);
+ }
+
+
+
+}
+
+void
+GroupTest::testGroupIndexOrder()
+{
+ uint16_t numGroups=10;
+
+ std::vector<Group*> groups;
+ for (uint16_t i=0; i< numGroups; ++i){
+ MAKEGROUPPTR(g, "group", i, "5.3|*");
+ groups.push_back(g);
+ }
+
+ for (uint16_t i=1; i< 10; ++i){
+ groups[0]->addSubGroup(groups[numGroups-i]);
+ }
+
+ uint16_t last=0;
+ for (uint16_t i=0; i< groups[0]->getNumSubGroups(); ++i){
+ CPPUNIT_ASSERT(last < groups[0]->getSubGroup(i)->getIndex());
+ last = groups[0]->getSubGroup(i)->getIndex();
+ }
+ delete groups[0];
+}
+
+
+void
+GroupTest::testNodeIndexOrder()
+{
+ uint16_t numNodes=10;
+ MAKEGROUP(g, "group", 0, "5.3|*");
+
+ for (uint16_t i=0; i< numNodes; ++i){
+ g.addNode(NodeType::DISTRIBUTOR, numNodes-i);
+ }
+
+ uint16_t last=0;
+ const std::vector<uint16_t>& nodes = g.getNodes(NodeType::DISTRIBUTOR);
+ CPPUNIT_ASSERT_EQUAL((size_t)numNodes, nodes.size());
+ for (uint16_t i=0; i< nodes.size(); ++i){
+ CPPUNIT_ASSERT(last < nodes[i]);
+ last = nodes[i];
+ }
+}
+
+
+void
+GroupTest::testIdealGroupRedundancyOrder()
+{
+ MAKEGROUPPTR(g0, "group0", 0, "1|2|*");
+ MAKEGROUPPTR(g1, "group1", 1, "*");
+ MAKEGROUPPTR(g2, "group2", 2, "*");
+ MAKEGROUPPTR(g3, "group3", 3, "*");
+
+ g0->addSubGroup(g1);
+ g0->addSubGroup(g2);
+ g0->addSubGroup(g3);
+
+ std::vector<IdealGroup> idealGroups;
+ g0->getIdealGroups(6, 100, idealGroups);
+
+ for (uint16_t i=0; i<idealGroups.size(); ++i){
+ CPPUNIT_ASSERT_EQUAL((double) (3-i), idealGroups[i].getRedundancy().getValue());
+ }
+ delete g0;
+}
+
+void
+GroupTest::testIdealGroupScoreOrder()
+{
+ MAKEGROUPPTR(g0, "group0", 0, "1|2|*");
+ MAKEGROUPPTR(g1, "group1", 1, "*");
+ MAKEGROUPPTR(g2, "group2", 2, "*");
+ MAKEGROUPPTR(g3, "group3", 3, "*");
+
+ g0->addSubGroup(g1);
+ g0->addSubGroup(g2);
+ g0->addSubGroup(g3);
+
+ std::vector<IdealGroup> idealGroups;
+ g0->getIdealGroups(6, 100, idealGroups);
+
+ std::sort(idealGroups.rbegin(), idealGroups.rend(), vdslib::IdealGroup::sortScore);
+ double last=1.0;
+ for (uint16_t g=0; g< idealGroups.size(); ++g){
+ CPPUNIT_ASSERT(last >= idealGroups[g].getScore());
+ last = idealGroups[g].getScore();
+ CPPUNIT_ASSERT_EQUAL((double) (g+1), idealGroups[g].getRedundancy().getValue());
+ }
+ delete g0;
+}
+
+
+void
+GroupTest::testIdealGroupPickingConsistency()
+{
+ MAKEGROUPPTR(g0, "group0", 0, "1|2|*");
+ MAKEGROUPPTR(g1, "group1", 1, "*");
+ MAKEGROUPPTR(g2, "group2", 2, "*");
+ MAKEGROUPPTR(g3, "group3", 3, "*");
+
+ g0->addSubGroup(g1);
+ g0->addSubGroup(g2);
+ g0->addSubGroup(g3);
+
+ std::vector<IdealGroup> idealGroups1;
+ g0->getIdealGroups(6, 100, idealGroups1);
+
+
+ std::vector<IdealGroup> idealGroups2;
+ g0->getIdealGroups(6, 100, idealGroups2);
+
+ CPPUNIT_ASSERT_EQUAL((size_t)3, idealGroups1.size());
+ CPPUNIT_ASSERT_EQUAL((size_t)3, idealGroups2.size());
+
+ for (uint16_t g=0; g< idealGroups1.size(); ++g){
+ CPPUNIT_ASSERT_EQUAL(idealGroups1[g].getGroup(),
+ idealGroups2[g].getGroup());
+ }
+ delete g0;
+}
diff --git a/vdslib/src/tests/state/nodestatetest.cpp b/vdslib/src/tests/state/nodestatetest.cpp
new file mode 100644
index 00000000000..e479dc70013
--- /dev/null
+++ b/vdslib/src/tests/state/nodestatetest.cpp
@@ -0,0 +1,110 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#include <vespa/fastos/fastos.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <vespa/vdslib/state/nodestate.h>
+#include <iostream>
+
+namespace storage {
+namespace lib {
+
+class NodeStateTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(NodeStateTest);
+ CPPUNIT_TEST(testParsing);
+ CPPUNIT_TEST(testExponential);
+ CPPUNIT_TEST(stateInstancesProvideDescriptiveNames);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+protected:
+ void testParsing();
+ void testExponential(); // Test exponential notation.
+ void stateInstancesProvideDescriptiveNames();
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION( NodeStateTest );
+
+void
+NodeStateTest::testParsing()
+{
+ {
+ NodeState ns = NodeState("s:u");
+ CPPUNIT_ASSERT_EQUAL(std::string("s:u"), ns.toString());
+ CPPUNIT_ASSERT_EQUAL(vespalib::Double(1.0), ns.getCapacity());
+ CPPUNIT_ASSERT_EQUAL(uint16_t(1), ns.getReliability());
+ }
+ {
+ NodeState ns = NodeState("s:m");
+ CPPUNIT_ASSERT_EQUAL(std::string("s:m"), ns.toString());
+ CPPUNIT_ASSERT_EQUAL(vespalib::Double(1.0), ns.getCapacity());
+ CPPUNIT_ASSERT_EQUAL(uint16_t(1), ns.getReliability());
+ }
+ {
+ NodeState ns = NodeState("t:4");
+ CPPUNIT_ASSERT_EQUAL(std::string("s:u t:4"), ns.toString());
+ CPPUNIT_ASSERT_EQUAL(uint64_t(4), ns.getStartTimestamp());
+ }
+ {
+ NodeState ns = NodeState("s:u c:2.4 r:3 b:12");
+ CPPUNIT_ASSERT_EQUAL(std::string("s:u c:2.4 r:3 b:12"), ns.toString());
+ CPPUNIT_ASSERT_EQUAL(vespalib::Double(2.4), ns.getCapacity());
+ CPPUNIT_ASSERT_EQUAL(uint16_t(3), ns.getReliability());
+ CPPUNIT_ASSERT_EQUAL(12, (int)ns.getMinUsedBits());
+
+ CPPUNIT_ASSERT(!(NodeState("s:u b:12") == NodeState("s:u b:13")));
+ }
+ {
+ NodeState ns = NodeState("c:2.4\ns:u\nr:5");
+ CPPUNIT_ASSERT_EQUAL(std::string("s:u c:2.4 r:5"), ns.toString());
+ CPPUNIT_ASSERT_EQUAL(vespalib::Double(2.4), ns.getCapacity());
+ CPPUNIT_ASSERT_EQUAL(uint16_t(5), ns.getReliability());
+ }
+ {
+ NodeState ns = NodeState("c:2.4 r:1");
+ CPPUNIT_ASSERT_EQUAL(std::string("s:u c:2.4"), ns.toString());
+ CPPUNIT_ASSERT_EQUAL(vespalib::Double(2.4), ns.getCapacity());
+ CPPUNIT_ASSERT_EQUAL(uint16_t(1), ns.getReliability());
+ }
+ {
+ NodeState ns = NodeState("c:2.4 k:2.6");
+ CPPUNIT_ASSERT_EQUAL(std::string("s:u c:2.4"), ns.toString());
+ CPPUNIT_ASSERT_EQUAL(vespalib::Double(2.4), ns.getCapacity());
+ CPPUNIT_ASSERT_EQUAL(uint16_t(1), ns.getReliability());
+ }
+}
+
+void
+NodeStateTest::testExponential()
+{
+ {
+ NodeState ns = NodeState("c:3E-8");
+ CPPUNIT_ASSERT_EQUAL( std::string("s:u c:3e-08"), ns.toString() );
+ CPPUNIT_ASSERT_EQUAL(vespalib::Double(3E-8), ns.getCapacity());
+ }
+ {
+ NodeState ns = NodeState("c:3e-08");
+ CPPUNIT_ASSERT_EQUAL( std::string("s:u c:3e-08"), ns.toString() );
+ CPPUNIT_ASSERT_EQUAL(vespalib::Double(3e-08), ns.getCapacity());
+ }
+}
+
+void
+NodeStateTest::stateInstancesProvideDescriptiveNames()
+{
+ CPPUNIT_ASSERT_EQUAL(vespalib::string("Unknown"),
+ State::UNKNOWN.getName());
+ CPPUNIT_ASSERT_EQUAL(vespalib::string("Maintenance"),
+ State::MAINTENANCE.getName());
+ CPPUNIT_ASSERT_EQUAL(vespalib::string("Down"),
+ State::DOWN.getName());
+ CPPUNIT_ASSERT_EQUAL(vespalib::string("Stopping"),
+ State::STOPPING.getName());
+ CPPUNIT_ASSERT_EQUAL(vespalib::string("Initializing"),
+ State::INITIALIZING.getName());
+ CPPUNIT_ASSERT_EQUAL(vespalib::string("Retired"),
+ State::RETIRED.getName());
+ CPPUNIT_ASSERT_EQUAL(vespalib::string("Up"),
+ State::UP.getName());
+}
+
+} // lib
+} // storage
diff --git a/vdslib/src/tests/testrunner.cpp b/vdslib/src/tests/testrunner.cpp
new file mode 100644
index 00000000000..fef61af9a17
--- /dev/null
+++ b/vdslib/src/tests/testrunner.cpp
@@ -0,0 +1,15 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/fastos/fastos.h>
+#include <vespa/log/log.h>
+#include <vespa/vdstestlib/cppunit/cppunittestrunner.h>
+
+LOG_SETUP("vdslibcppunittestrunner");
+
+int
+main(int argc, char **argv)
+{
+ vdstestlib::CppUnitTestRunner testRunner;
+ return testRunner.run(argc, argv);
+}
+
diff --git a/vdslib/src/tests/thread/.gitignore b/vdslib/src/tests/thread/.gitignore
new file mode 100644
index 00000000000..583460ae288
--- /dev/null
+++ b/vdslib/src/tests/thread/.gitignore
@@ -0,0 +1,3 @@
+*.So
+.depend
+Makefile
diff --git a/vdslib/src/tests/thread/CMakeLists.txt b/vdslib/src/tests/thread/CMakeLists.txt
new file mode 100644
index 00000000000..210ecae3440
--- /dev/null
+++ b/vdslib/src/tests/thread/CMakeLists.txt
@@ -0,0 +1,6 @@
+# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_library(vdslib_testthread
+ SOURCES
+ taskschedulertest.cpp
+ DEPENDS
+)
diff --git a/vdslib/src/tests/thread/taskschedulertest.cpp b/vdslib/src/tests/thread/taskschedulertest.cpp
new file mode 100644
index 00000000000..ef4be409ebc
--- /dev/null
+++ b/vdslib/src/tests/thread/taskschedulertest.cpp
@@ -0,0 +1,244 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/fastos/fastos.h>
+#include <vespa/vdslib/thread/taskscheduler.h>
+#include <vespa/vdstestlib/cppunit/macros.h>
+
+namespace vdslib {
+
+struct TaskSchedulerTest : public CppUnit::TestFixture {
+ void testSimple();
+ void testMultipleTasksAtSameTime();
+ void testRemoveTask();
+
+ CPPUNIT_TEST_SUITE(TaskSchedulerTest);
+ CPPUNIT_TEST(testSimple);
+ CPPUNIT_TEST(testMultipleTasksAtSameTime);
+ CPPUNIT_TEST(testRemoveTask);
+ CPPUNIT_TEST_SUITE_END();
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(TaskSchedulerTest);
+
+namespace {
+
+struct TestWatch : public TaskScheduler::Watch {
+ vespalib::Lock _lock;
+ uint64_t _time;
+
+ TestWatch(uint64_t startTime = 0) : _time(startTime) {}
+ ~TestWatch() {}
+
+ TaskScheduler::Time getTime() const {
+ vespalib::LockGuard guard(_lock);
+ return _time;
+ }
+
+ void increment(uint64_t ms) {
+ vespalib::LockGuard guard(_lock);
+ _time += ms;
+ }
+
+ void set(uint64_t ms) {
+ vespalib::LockGuard guard(_lock);
+ _time = ms;
+ }
+};
+
+struct TestTask : public TaskScheduler::Task
+{
+ TestWatch& _watch;
+ uint64_t _executionTime;
+ uint64_t _maxRuns;
+ uint64_t _maxTime;
+ int64_t _result;
+ uint64_t _currentRuns;
+ std::string _name;
+ std::vector<std::string>* _register;
+
+ TestTask(TestWatch& watch, uint64_t executionTime, uint64_t maxRuns,
+ uint64_t maxTime, int64_t result)
+ : _watch(watch), _executionTime(executionTime), _maxRuns(maxRuns),
+ _maxTime(maxTime), _result(result), _currentRuns(0),
+ _name(), _register(0)
+ {
+ }
+
+ void registerCallsWithName(const std::string& name,
+ std::vector<std::string>& myregister)
+ {
+ _name = name;
+ _register = &myregister;
+ }
+
+ int64_t run(TaskScheduler::Time currentTime) {
+ // Emulate that we use time to run
+ _watch.increment(_executionTime);
+ if (_register != 0) {
+ std::ostringstream ost;
+ ost << currentTime;
+ if (_name.size() > 0) {
+ ost << " " << _name;
+ }
+ _register->push_back(ost.str());
+ }
+ // If max runs, dont run anymore
+ if (++_currentRuns >= _maxRuns) {
+ //std::cerr << "Max runs run, returning 0\n";
+ return 0;
+ }
+ // If we will go beyond max time, dont run anymore
+ if (_result > 0 && currentTime + _result > _maxTime) {
+ //std::cerr << "Max time spent, returning 0\n";
+ return 0;
+ }
+ //std::cerr << "Executed test task. Returning " << _result << "\n";
+ return _result;
+ }
+
+};
+
+std::string join(std::vector<std::string>& v) {
+ std::ostringstream ost;
+ for (size_t i=0; i<v.size(); ++i) {
+ if (i != 0) ost << ",";
+ ost << v[i];
+ }
+ return ost.str();
+}
+
+} // End of anonymous namespace
+
+void
+TaskSchedulerTest::testSimple()
+{
+ FastOS_ThreadPool threadPool(128 * 1024);
+ TestWatch watch(0);
+ TaskScheduler scheduler;
+ scheduler.setWatch(watch);
+ scheduler.start(threadPool);
+ std::vector<std::string> calls;
+
+ // Test that one can schedule a single task immediately
+ {
+ calls.clear();
+ watch.set(0);
+ uint64_t counter = scheduler.getTaskCounter();
+ TestTask* task(new TestTask(watch, 10, 5, 1000, 0));
+ task->registerCallsWithName("", calls);
+ scheduler.add(TestTask::UP(task));
+ scheduler.waitForTaskCounterOfAtLeast(counter + 1);
+ CPPUNIT_ASSERT_EQUAL(std::string("0"), join(calls));
+ scheduler.waitUntilNoTasksRemaining(); // Ensure task is complete
+ }
+ // Test that task is repeated at intervals if wanted.
+ {
+ calls.clear();
+ watch.set(0);
+ uint64_t counter = scheduler.getTaskCounter();
+ TestTask* task(new TestTask(watch, 10, 5, 1000, -20));
+ task->registerCallsWithName("", calls);
+ scheduler.add(TestTask::UP(task));
+ for (uint32_t i = 1; i <= 5; ++i) {
+ scheduler.waitForTaskCounterOfAtLeast(counter + i);
+ watch.increment(100);
+ }
+ CPPUNIT_ASSERT_EQUAL(std::string("0,110,220,330,440"),
+ join(calls));
+ scheduler.waitUntilNoTasksRemaining(); // Ensure task is complete
+ }
+ // Test that task scheduled at specific time works, and that if
+ // scheduled at specific time in the past/current, we're rerun at once.
+ {
+ calls.clear();
+ watch.set(0);
+ uint64_t counter = scheduler.getTaskCounter();
+ TestTask* task(new TestTask(watch, 10, 4, 1000, 100));
+ task->registerCallsWithName("", calls);
+ scheduler.addAbsolute(TestTask::UP(task), 50);
+ watch.increment(49); // Not yet time to run
+ FastOS_Thread::Sleep(5);
+ // Check that it has not run yet..
+ CPPUNIT_ASSERT_EQUAL(counter, scheduler.getTaskCounter());
+ watch.increment(10); // Now time is enough for it to run
+ scheduler.waitForTaskCounterOfAtLeast(counter + 1);
+ watch.increment(10);
+ FastOS_Thread::Sleep(5);
+ // Check that it has not run yet..
+ CPPUNIT_ASSERT_EQUAL(counter + 1, scheduler.getTaskCounter());
+ watch.increment(50);
+ scheduler.waitForTaskCounterOfAtLeast(counter + 2);
+ CPPUNIT_ASSERT_EQUAL(std::string("59,129,129,129"),
+ join(calls));
+ scheduler.waitUntilNoTasksRemaining(); // Ensure task is complete
+ }
+}
+
+void
+TaskSchedulerTest::testMultipleTasksAtSameTime()
+{
+ FastOS_ThreadPool threadPool(128 * 1024);
+ TestWatch watch(0);
+ TaskScheduler scheduler;
+ scheduler.setWatch(watch);
+ std::vector<std::string> calls;
+
+ // Test that tasks deleted before they are run are automatically
+ // cancelled and removed from scheduler
+ {
+ TestTask* task1(new TestTask(watch, 10, 3, 1000, 10));
+ TestTask* task2(new TestTask(watch, 10, 3, 1000, 10));
+ task1->registerCallsWithName("task1", calls);
+ task2->registerCallsWithName("task2", calls);
+ watch.set(10);
+ scheduler.add(TestTask::UP(task1));
+ scheduler.add(TestTask::UP(task2));
+ // Start threadpool after adding both, such that we ensure both
+ // are added at the same time interval
+ scheduler.start(threadPool);
+
+ scheduler.waitUntilNoTasksRemaining(); // Ensure task is complete
+ std::ostringstream ost;
+ for (size_t i=0; i<calls.size(); ++i) ost << calls[i] << "\n";
+
+ CPPUNIT_ASSERT_EQUAL(std::string(
+ "10 task1\n"
+ "10 task2\n"
+ "10 task1\n"
+ "10 task2\n"
+ "10 task1\n"
+ "10 task2\n"
+ ), ost.str());
+ }
+}
+
+void
+TaskSchedulerTest::testRemoveTask()
+{
+ FastOS_ThreadPool threadPool(128 * 1024);
+ TestWatch watch(0);
+ TaskScheduler scheduler;
+ scheduler.setWatch(watch);
+ scheduler.start(threadPool);
+ std::vector<std::string> calls;
+
+ // Schedule a task, and remove it..
+ {
+ calls.clear();
+ watch.set(0);
+ TestTask* task(new TestTask(watch, 10, 5, 1000, 0));
+ task->registerCallsWithName("", calls);
+ scheduler.addAbsolute(TestTask::UP(task), 50);
+ // Remove actual task
+ scheduler.remove(task);
+ scheduler.waitUntilNoTasksRemaining(); // Ensure task is complete
+ // Remove non-existing task
+ task = new TestTask(watch, 10, 5, 1000, 0);
+ scheduler.remove(task);
+ delete task;
+ // Time should not be advanced as task didn't get to run
+ CPPUNIT_ASSERT_EQUAL(0, (int) watch.getTime());
+ }
+}
+
+}
diff --git a/vdslib/src/vespa/vdslib/.gitignore b/vdslib/src/vespa/vdslib/.gitignore
new file mode 100644
index 00000000000..638c8dbed51
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/.gitignore
@@ -0,0 +1,3 @@
+.depend
+Makefile
+/libvdslib.so.5.1
diff --git a/vdslib/src/vespa/vdslib/CMakeLists.txt b/vdslib/src/vespa/vdslib/CMakeLists.txt
new file mode 100644
index 00000000000..0264a5ed15d
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/CMakeLists.txt
@@ -0,0 +1,11 @@
+# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_library(vdslib
+ SOURCES
+ bucketdistribution.cpp
+ $<TARGET_OBJECTS:vdslib_container>
+ $<TARGET_OBJECTS:vdslib_state>
+ $<TARGET_OBJECTS:vdslib_distribution>
+ $<TARGET_OBJECTS:vdslib_thread>
+ INSTALL lib64
+ DEPENDS
+)
diff --git a/vdslib/src/vespa/vdslib/bucketdistribution.cpp b/vdslib/src/vespa/vdslib/bucketdistribution.cpp
new file mode 100644
index 00000000000..95bf7a7cd1d
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/bucketdistribution.cpp
@@ -0,0 +1,115 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#include <vespa/fastos/fastos.h>
+#include <vespa/log/log.h>
+LOG_SETUP(".bucketdistribution");
+
+#include "bucketdistribution.h"
+
+namespace vdslib {
+
+BucketDistribution::BucketDistribution(uint32_t numColumns, uint32_t numBucketBits) :
+ _numColumns(0),
+ _numBucketBits(numBucketBits),
+ _bucketToColumn(),
+ _lock()
+{
+ _bucketToColumn.resize(getNumBuckets());
+ reset();
+ setNumColumns(numColumns);
+}
+
+void
+BucketDistribution::getBucketCount(uint32_t numColumns, uint32_t numBucketBits, std::vector<uint32_t> &ret)
+{
+ ret.resize(numColumns);
+ uint32_t cnt = getNumBuckets(numBucketBits) / numColumns;
+ uint32_t rst = getNumBuckets(numBucketBits) % numColumns;
+ for (uint32_t i = 0; i < numColumns; ++i) {
+ ret[i] = cnt + (i < rst ? 1 : 0);
+ }
+}
+
+void
+BucketDistribution::getBucketMigrateCount(uint32_t numColumns, uint32_t numBucketBits, std::vector<uint32_t> &ret)
+{
+ getBucketCount(numColumns++, numBucketBits, ret);
+ uint32_t cnt = getNumBuckets(numBucketBits) / numColumns;
+ uint32_t rst = getNumBuckets(numBucketBits) % numColumns;
+ for (uint32_t i = 0; i < numColumns - 1; ++i) {
+ ret[i] -= cnt + (i < rst ? 1 : 0);
+ }
+}
+
+void
+BucketDistribution::reset()
+{
+ for (std::vector<uint32_t>::iterator it = _bucketToColumn.begin();
+ it != _bucketToColumn.end(); ++it) {
+ *it = 0;
+ }
+ _numColumns = 1;
+}
+
+void
+BucketDistribution::addColumn()
+{
+ uint32_t newColumns = _numColumns + 1;
+ std::vector<uint32_t> migrate;
+ getBucketMigrateCount(_numColumns, _numBucketBits, migrate);
+ uint32_t numBuckets = getNumBuckets(_numBucketBits);
+ for (uint32_t i = 0; i < numBuckets; ++i) {
+ uint32_t old = _bucketToColumn[i];
+ if (migrate[old] > 0) {
+ _bucketToColumn[i] = _numColumns; // move this bucket to the new column
+ migrate[old]--;
+ }
+ }
+ _numColumns = newColumns;
+}
+
+void
+BucketDistribution::setNumColumns(uint32_t numColumns)
+{
+ vespalib::LockGuard guard(_lock);
+ if (numColumns < _numColumns) {
+ reset();
+ }
+ if (numColumns == _numColumns) {
+ return;
+ }
+ for (int i = numColumns - _numColumns; --i >= 0; ) {
+ addColumn();
+ }
+}
+
+void
+BucketDistribution::setNumBucketBits(uint32_t numBucketBits)
+{
+ uint32_t numColumns;
+ {
+ vespalib::LockGuard guard(_lock);
+ if (numBucketBits == _numBucketBits) {
+ return;
+ }
+ _numBucketBits = numBucketBits;
+ _bucketToColumn.resize(getNumBuckets(numBucketBits));
+ numColumns = _numColumns;
+ reset();
+ }
+ setNumColumns(numColumns);
+}
+
+uint32_t
+BucketDistribution::getColumn(const document::BucketId &bucketId) const
+{
+ uint32_t ret = (uint32_t)(bucketId.getId() & (getNumBuckets(_numBucketBits) - 1));
+ if (ret >= _bucketToColumn.size()) {
+ LOG(error,
+ "The bucket distribution map is not in sync with the number of bucket bits. "
+ "This should never happen! Distribution is broken!!");
+ return 0;
+ }
+ return _bucketToColumn[ret];
+}
+
+}
diff --git a/vdslib/src/vespa/vdslib/bucketdistribution.h b/vdslib/src/vespa/vdslib/bucketdistribution.h
new file mode 100644
index 00000000000..b7064a43ee3
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/bucketdistribution.h
@@ -0,0 +1,119 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#pragma once
+
+#include <vector>
+#include <vespa/document/bucket/bucketid.h>
+#include <vespa/vespalib/util/sync.h>
+
+namespace vdslib {
+
+/**
+ * Stable algorithmic hash distribution; this class assigns hash buckets to targets. The number of hash buckets should
+ * be large compared to the number of targets. The mapping from hash value to hash bucket is performed outside this
+ * class.
+ */
+class BucketDistribution {
+public:
+ /**
+ * Constructs a new bucket distribution object with a given number of columns and buckets.
+ *
+ * @param numColumns The number of columns to distribute to.
+ * @param numBucketBits The number of bits to use for bucket id.
+ */
+ BucketDistribution(uint32_t numColumns, uint32_t numBucketBits);
+
+ /**
+ * Returns the number of buckets that the given number of bucket bits will allow.
+ *
+ * @param numBucketBits The number of bits to use for bucket id.
+ * @return The number of buckets allowed.
+ */
+ static uint32_t getNumBuckets(uint32_t numBucketBits) { return 1 << numBucketBits; }
+
+ /**
+ * This method returns a list that contains the distributions of the given number of buckets over the given number
+ * of columns.
+ *
+ * @param numColumns The number of columns to distribute to.
+ * @param numBucketBits The number of bits to use for bucket id.
+ * @param ret List to fill with the bucket distribution.
+ */
+ static void getBucketCount(uint32_t numColumns, uint32_t numBucketBits, std::vector<uint32_t> &ret);
+
+ /**
+ * This method returns a list similar to {@link this#getBucketCount(int,int)}, except that the returned list
+ * contains the number of buckets that will have to be migrated from each column if an additional column was added.
+ *
+ * @param numColumns The original number of columns.
+ * @param numBucketBits The number of bits to use for bucket id.
+ * @param ret List to fill with the number of buckets to migrate, one value per column.
+ */
+ static void getBucketMigrateCount(uint32_t numColumns, uint32_t numBucketBits, std::vector<uint32_t> &ret);
+
+ /**
+ * Sets the number of columns to distribute to to 1, and resets the content of the internal bucket-to-column map so
+ * that it all buckets point to that single column.
+ */
+ void reset();
+
+ /**
+ * Sets the number of columns to use for this document distribution object. This will reset and setup this object
+ * from scratch. The original number of buckets is maintained.
+ *
+ * @param numColumns The new number of columns to distribute to.
+ */
+ void setNumColumns(uint32_t numColumns);
+
+ /**
+ * Returns the number of columns to distribute to.
+ *
+ * @return The number of columns.
+ */
+ uint32_t getNumColumns() const { return _numColumns; }
+
+ /**
+ * Sets the number of buckets to use for this document distribution object. This will reset and setup this object
+ * from scratch. The original number of columns is maintained.
+ *
+ * @param numBucketBits The new number of bits to use for bucket id.
+ */
+ void setNumBucketBits(uint32_t numBucketBits);
+
+ /**
+ * Returns the number of bits used for bucket identifiers.
+ *
+ * @return The number of bits.
+ */
+ uint32_t getNumBucketBits() const { return _numBucketBits; }
+
+ /**
+ * Returns the number of buckets available using the configured number of bucket bits.
+ *
+ * @return The number of buckets.
+ */
+ uint32_t getNumBuckets() const { return getNumBuckets(_numBucketBits); }
+
+ /**
+ * This method maps the given bucket id to its corresponding column.
+ *
+ * @param bucketId The bucket whose column to lookup.
+ * @return The column to distribute the bucket to.
+ */
+ uint32_t getColumn(const document::BucketId &bucketId) const;
+
+private:
+ /**
+ * Adds a single column to this bucket distribution object. This will modify the internal bucket-to-column map so
+ * that it takes into account the new column.
+ */
+ void addColumn();
+
+private:
+ uint32_t _numColumns; // The number of columns to distribute to.
+ uint32_t _numBucketBits; // The number of bits to use for bucket identification.
+ std::vector<uint32_t> _bucketToColumn; // A map from bucket id to column index.
+ vespalib::Lock _lock;
+};
+
+}
+
diff --git a/vdslib/src/vespa/vdslib/container/.gitignore b/vdslib/src/vespa/vdslib/container/.gitignore
new file mode 100644
index 00000000000..5dae353d999
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/container/.gitignore
@@ -0,0 +1,2 @@
+.depend
+Makefile
diff --git a/vdslib/src/vespa/vdslib/container/CMakeLists.txt b/vdslib/src/vespa/vdslib/container/CMakeLists.txt
new file mode 100644
index 00000000000..606ac570688
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/container/CMakeLists.txt
@@ -0,0 +1,15 @@
+# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_library(vdslib_container OBJECT
+ SOURCES
+ dummycppfile.cpp
+ documentlist.cpp
+ mutabledocumentlist.cpp
+ writabledocumentlist.cpp
+ parameters.cpp
+ searchresult.cpp
+ documentsummary.cpp
+ operationlist.cpp
+ visitorstatistics.cpp
+ visitorordering.cpp
+ DEPENDS
+)
diff --git a/vdslib/src/vespa/vdslib/container/documentlist.cpp b/vdslib/src/vespa/vdslib/container/documentlist.cpp
new file mode 100644
index 00000000000..352302f3a1f
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/container/documentlist.cpp
@@ -0,0 +1,498 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#include <vespa/fastos/fastos.h>
+#include <vespa/vdslib/container/documentlist.h>
+
+#include <vespa/log/log.h>
+#include <vespa/vespalib/util/exceptions.h>
+
+LOG_SETUP(".vdslib.container.documentlist");
+
+using document::ByteBuffer;
+
+namespace vdslib {
+
+DocumentList::MetaEntry::MetaEntry()
+{
+ memset(this, 0, sizeof(MetaEntry));
+}
+
+void
+DocumentList::MetaEntry::print(std::ostream& out, const std::string& indent) const
+{
+ (void) indent;
+ out << "MetaEntry(Ts 0x" << std::hex << timestamp << ", h "
+ << headerPos << "/" << headerLen << ", b " << bodyPos << "/" << bodyLen;
+ if (flags & REMOVE_ENTRY) out << ", remove";
+ if (flags & BODY_STRIPPED) out << ", body stripped";
+ if (flags & BODY_IN_HEADER) out << ", body in header";
+ out << ")";
+}
+
+DocumentList::Entry::Entry(char* start, uint32_t entry,
+ const document::DocumentTypeRepo &repo)
+ : _metaEntry(reinterpret_cast<MetaEntry*>(
+ start + sizeof(uint32_t) + entry * sizeof(MetaEntry))),
+ _start(start),
+ _entry(entry),
+ _repo(&repo)
+{
+}
+
+DocumentList::Entry
+DocumentList::Entry::next() const
+{
+ if (_entry + 1 >= *reinterpret_cast<uint32_t*>(_start)) {
+ return Entry();
+ }
+ return Entry(_start, _entry + 1, *_repo);
+}
+
+document::DocumentId
+DocumentList::Entry::getDocumentId() const
+{
+ ByteBuffer buf(_start + _metaEntry->headerPos, _metaEntry->headerLen);
+ try {
+ if (isUpdateEntry()) {
+ document::DocumentUpdate::UP update(
+ document::DocumentUpdate::create42(*_repo, buf));
+ return update->getId();
+ } else {
+ return document::Document::getIdFromSerialized(buf);
+ }
+ } catch (const document::DeserializeException& e) {
+ std::ostringstream ss;
+ ss << "Failed to deserialize document ID from " << *this;
+ throw document::DeserializeException(ss.str(), e, VESPA_STRLOC);
+ }
+}
+
+std::unique_ptr<document::Document>
+DocumentList::Entry::getDocument(
+ const document::DocumentType *anticipatedType) const
+{
+ if (isUpdateEntry()) {
+ throw vespalib::IllegalStateException("Entry contains an update. "
+ "Call getUpdate(), not getDocument()", VESPA_STRLOC);
+ }
+ ByteBuffer hbuf(_start + _metaEntry->headerPos, _metaEntry->headerLen);
+ ByteBuffer bbuf(_start + _metaEntry->bodyPos, _metaEntry->bodyLen);
+ std::unique_ptr<document::Document> doc;
+ try {
+ if (_metaEntry->bodyLen == 0) {
+ doc.reset(new document::Document(*_repo, hbuf, anticipatedType));
+ } else {
+ doc.reset(new document::Document(*_repo, hbuf, bbuf,
+ anticipatedType));
+ }
+ } catch (const document::DeserializeException& e) {
+ std::ostringstream ss;
+ ss << "Failed to deserialize document from " << *this;
+ throw document::DeserializeException(ss.str(), e, VESPA_STRLOC);
+ }
+ if (hbuf.getRemaining() != 0 || bbuf.getRemaining() != 0) {
+ assert(hbuf.getPos() + hbuf.getRemaining() == hbuf.getLength());
+ assert(bbuf.getPos() + bbuf.getRemaining() == bbuf.getLength());
+ throw document::DeserializeException(vespalib::make_string(
+ "Deserializing document %s, only %lu of %lu header bytes and "
+ "%lu of %lu body bytes were consumed.",
+ doc->getId().toString().c_str(),
+ hbuf.getPos(), hbuf.getLength(),
+ bbuf.getPos(), bbuf.getLength()), VESPA_STRLOC);
+ }
+ doc->setLastModified(_metaEntry->timestamp);
+ return doc;
+}
+
+std::unique_ptr<document::Document>
+DocumentList::Entry::getHeader(
+ const document::DocumentType *anticipatedType) const
+{
+ if (isUpdateEntry()) {
+ throw vespalib::IllegalStateException("Entry contains an update. "
+ "Call getUpdate(), not getDocument()", VESPA_STRLOC);
+ }
+ ByteBuffer hbuf(_start + _metaEntry->headerPos, _metaEntry->headerLen);
+ std::unique_ptr<document::Document> doc(
+ new document::Document(*_repo, hbuf, anticipatedType));
+ if (hbuf.getRemaining() != 0) {
+ assert(hbuf.getPos() + hbuf.getRemaining() == hbuf.getLength());
+ throw document::DeserializeException(vespalib::make_string(
+ "Deserializing header of document %s, only %lu of %lu header "
+ "bytes were consumed.",
+ doc->getId().toString().c_str(),
+ hbuf.getPos(), hbuf.getLength()), VESPA_STRLOC);
+ }
+ doc->setLastModified(_metaEntry->timestamp);
+ return doc;
+}
+
+std::unique_ptr<document::DocumentUpdate>
+DocumentList::Entry::getUpdate() const
+{
+ if (!isUpdateEntry()) {
+ throw vespalib::IllegalStateException("Entry contains a document. "
+ "Call getDocument(), not getUpdate()", VESPA_STRLOC);
+ }
+ assert(_metaEntry->bodyLen == 0);
+ ByteBuffer buf(_start + _metaEntry->headerPos, _metaEntry->headerLen);
+ document::DocumentUpdate::UP update(
+ document::DocumentUpdate::create42(*_repo, buf));
+ if (buf.getRemaining() != 0) {
+ assert(buf.getPos() + buf.getRemaining() == buf.getLength());
+ throw document::DeserializeException(vespalib::make_string(
+ "Deserializing document update %s, only %lu of %lu bytes "
+ "were consumed.",
+ update->getId().toString().c_str(),
+ buf.getPos(), buf.getLength()), VESPA_STRLOC);
+ }
+ return update;
+}
+
+bool
+DocumentList::Entry::getDocument(document::Document& doc, bool longLivedBuffer) const
+{
+ if (isUpdateEntry()) {
+ throw vespalib::IllegalStateException("Entry contains an update. "
+ "Call getUpdate(), not getDocument()", VESPA_STRLOC);
+ }
+ ByteBuffer hbuf(_start + _metaEntry->headerPos, _metaEntry->headerLen);
+
+ if (_metaEntry->flags & MetaEntry::BODY_IN_HEADER ||
+ _metaEntry->bodyLen == 0)
+ {
+ doc.deserialize(*_repo, hbuf, longLivedBuffer);
+ doc.setLastModified(getTimestamp());
+ } else {
+ ByteBuffer cbuf(_start + _metaEntry->bodyPos, _metaEntry->bodyLen);
+ doc.deserialize(*_repo, hbuf, cbuf, longLivedBuffer);
+ doc.setLastModified(getTimestamp());
+ }
+ return true;
+}
+
+bool
+DocumentList::Entry::getHeader(document::Document& doc) const
+{
+ if (isUpdateEntry()) {
+ throw vespalib::IllegalStateException("Entry contains an update. "
+ "Call getUpdate(), not getDocument()", VESPA_STRLOC);
+ }
+ ByteBuffer hbuf(_start + _metaEntry->headerPos, _metaEntry->headerLen);
+ doc.deserialize(*_repo, hbuf);
+ doc.setLastModified(_metaEntry->timestamp);
+ return (hbuf.getRemaining() == 0);
+}
+
+bool
+DocumentList::Entry::getUpdate(document::DocumentUpdate& update) const
+{
+ if (!isUpdateEntry()) {
+ throw vespalib::IllegalStateException("Entry contains a document. "
+ "Call getDocument(), not getUpdate()", VESPA_STRLOC);
+ }
+ ByteBuffer buf(_start + _metaEntry->headerPos, _metaEntry->headerLen);
+ assert(_metaEntry->bodyLen == 0);
+ update.deserialize42(*_repo, buf);
+ return (buf.getRemaining() == 0);
+}
+
+
+const DocumentList::Entry::BufferPosition
+DocumentList::Entry::getRawHeader() const
+{
+ return BufferPosition(_start + _metaEntry->headerPos,
+ _metaEntry->headerLen);
+}
+
+const DocumentList::Entry::BufferPosition
+DocumentList::Entry::getRawBody() const
+{
+ return BufferPosition(_start + _metaEntry->bodyPos, _metaEntry->bodyLen);
+}
+
+void
+DocumentList::Entry::print(std::ostream& out, bool verbose,
+ const std::string& indent) const
+{
+ out << "DocEntry(Timestamp: " << getTimestamp();
+ if (isRemoveEntry()) out << ", removed";
+ out << ", (h p/s " << _metaEntry->headerPos << "/" << _metaEntry->headerLen
+ << ", b " << _metaEntry->bodyPos << "/" << _metaEntry->bodyLen << ")";
+ if (verbose) {
+ vespalib::string escaped;
+ if (_metaEntry->headerLen > 0 && _metaEntry->headerLen < 256) {
+ vespalib::string header(_start+_metaEntry->headerPos, _metaEntry->headerLen);
+ out << "\n" << indent << " "
+ << document::StringUtil::escape(header, escaped);
+ }
+ if (_metaEntry->bodyLen > 0 && _metaEntry->bodyLen < 256) {
+ vespalib::string body(_start + _metaEntry->bodyPos, _metaEntry->bodyLen);
+ out << "\n" << indent << " "
+ << document::StringUtil::escape(body, escaped);
+ }
+ }
+ out << ")";
+}
+
+DocumentList::const_iterator& DocumentList::const_iterator::operator++()
+{
+ assert(_entry.valid());
+ _entry = _entry.next();
+ return *this;
+}
+
+DocumentList::const_iterator DocumentList::const_iterator::operator++(int)
+{
+ const_iterator it(_entry);
+ operator++();
+ return it;
+}
+
+bool DocumentList::const_iterator::operator==(const const_iterator& it) const
+{
+ return (_entry == it._entry);
+}
+
+bool DocumentList::const_iterator::operator!=(const const_iterator& it) const
+{
+ return !(_entry == it._entry);
+}
+
+
+DocumentList::DocumentList(const document::DocumentTypeRepo::SP & repo, char* buffer, uint32_t bufferSize, bool keepexisting)
+ : _buffer(buffer),
+ _bufferSize(bufferSize),
+ _wasted(0),
+ _freePtr(buffer),
+ _repo(repo)
+{
+ init(keepexisting);
+}
+
+void DocumentList::init(bool keepexisting)
+{
+ if (_buffer == 0) {
+ assert(_bufferSize == 0);
+ return;
+ }
+ assert(_bufferSize > sizeof(uint32_t));
+ if (keepexisting) {
+ uint32_t min = 0xFFFFFFFF;
+ for (uint32_t i=0, n=docCount(); i<n; ++i) {
+ MetaEntry& entry(getMeta(i));
+ if (entry.headerLen > 0 && entry.headerPos < min) {
+ min = entry.headerPos;
+ }
+ if (entry.bodyLen > 0 && entry.bodyPos < min) {
+ min = entry.bodyPos;
+ }
+ }
+ if (docCount() > 0) {
+ assert(min < _bufferSize);
+ _freePtr += min;
+ } else {
+ _freePtr += _bufferSize;
+ }
+ } else {
+ docCount() = 0;
+ _freePtr += _bufferSize;
+ }
+ checkConsistency();
+}
+
+DocumentList::DocumentList(const DocumentList& source,
+ char* buffer, uint32_t bufferSize)
+ : _buffer(buffer),
+ _bufferSize(bufferSize),
+ _wasted(0),
+ _freePtr(buffer),
+ _repo(source._repo)
+{
+ assert(buffer == 0 ? bufferSize == 0 : bufferSize >= sizeof(uint32_t));
+ if (source.size() == 0) {
+ if (buffer != 0) {
+ docCount() = 0;
+ _freePtr += bufferSize;
+ }
+ return;
+ }
+
+ // If we get here we know that source contains documents
+ uint32_t n = source.docCount();
+ uint64_t need = source.spaceNeeded();
+
+ if (need > bufferSize) {
+ std::ostringstream ost;
+ ost << "Cannot create a documentlist of size " << bufferSize
+ << " bytes containing the data of documentlist of size "
+ << source.getBufferSize() << ", needing " << need
+ << " bytes minimum.";
+ throw vespalib::IllegalArgumentException(ost.str(), VESPA_STRLOC);
+ }
+ // If we get here we know that this object has enough space to fit all
+ uint32_t pos = bufferSize;
+ for (uint32_t i = 0; i < n; ++i) {
+ MetaEntry& entry(getMeta(i) = source.getMeta(i));
+
+ pos -= entry.bodyLen;
+ memcpy(_buffer + pos, source._buffer + entry.bodyPos, entry.bodyLen);
+ entry.bodyPos = pos;
+
+ pos -= entry.headerLen;
+ memcpy(_buffer + pos, source._buffer + entry.headerPos, entry.headerLen);
+ entry.headerPos = pos;
+ }
+ _freePtr = _buffer + pos;
+ docCount() = n;
+ checkConsistency();
+}
+
+DocumentList::~DocumentList()
+{
+}
+
+DocumentList::DocumentList(const DocumentList &rhs)
+ : document::Printable(rhs),
+ _buffer(rhs._buffer),
+ _bufferSize(rhs._bufferSize),
+ _wasted(rhs._wasted),
+ _freePtr(rhs._freePtr),
+ _repo(rhs._repo)
+{
+ checkConsistency();
+}
+
+DocumentList&
+DocumentList::operator=(const DocumentList &rhs)
+{
+ document::Printable::operator=(rhs);
+ _buffer = rhs._buffer;
+ _bufferSize = rhs._bufferSize;
+ _wasted = rhs._wasted;
+ _freePtr = rhs._freePtr;
+ _repo = _repo;
+ checkConsistency();
+ return *this;
+}
+
+namespace {
+struct PosLen {
+ uint32_t pos;
+ uint32_t len;
+ PosLen() : pos(0), len(0) {};
+ bool operator< (const PosLen& other) const { return pos < other.pos; }
+};
+} // namespace
+
+void
+DocumentList::checkConsistency(bool do_memset)
+{
+ unsigned long need = spaceNeeded();
+ unsigned long free = countFree();
+ unsigned long bsiz = getBufferSize();
+ if (do_memset || need + free + _wasted != bsiz) {
+ std::vector<PosLen> blocks;
+ uint32_t n = docCount();
+ for (uint32_t i = 0; i < n; ++i) {
+ MetaEntry& entry(getMeta(i));
+ if (entry.headerLen > 0) {
+ PosLen pl;
+ pl.pos = entry.headerPos;
+ pl.len = entry.headerLen;
+ blocks.push_back(pl);
+ }
+ if (entry.bodyLen > 0) {
+ PosLen pl;
+ pl.pos = entry.bodyPos;
+ pl.len = entry.bodyLen;
+ blocks.push_back(pl);
+ }
+ }
+ std::sort(blocks.begin(), blocks.end());
+ _wasted = 0;
+ uint32_t prevStart = bsiz;
+ uint32_t prevLength = 0;
+ for (uint32_t i = blocks.size(); i-- > 0; ) {
+ uint32_t curEnd = blocks[i].pos + blocks[i].len;
+ if (curEnd > prevStart
+ && (blocks[i].pos != prevStart
+ || blocks[i].len != prevLength))
+ {
+ LOG(error, "DocumentList has overlapping blocks (block %u: curEnd(%u) > prevStart(%u))",
+ i, curEnd, prevStart);
+ std::ostringstream oss;
+ print(oss, true, "");
+ std::cerr << "Dumping DocumentList: " << oss.str() << "\n";
+ assert(!"DocumentList has overlapping blocks!");
+ }
+ if (curEnd < prevStart) {
+ uint32_t len = prevStart - curEnd;
+ if (do_memset) {
+ LOG(debug, "waste %u bytes filled with 0xFF", len);
+ memset(_buffer + curEnd, 0xff, len);
+ }
+ _wasted += len;
+ }
+ prevStart = blocks[i].pos;
+ prevLength = blocks[i].len;
+ }
+ if (_freePtr > _buffer + prevStart) {
+ assert(!"_freePtr inside data block");
+ }
+ if (_freePtr < _buffer + prevStart) {
+ // may be needed for alignment
+ uint32_t len = _buffer + prevStart - _freePtr;
+ if (do_memset) {
+ LOG(debug, "waste %u bytes before start, filled with 0xFF", len);
+ memset(_freePtr, 0xFF, len);
+ }
+ _wasted += len;
+ }
+ if (_freePtr < _buffer + sizeof(uint32_t) + sizeof(MetaEntry)*size()) {
+ assert(!"_freePtr inside meta block");
+ }
+ }
+}
+
+void
+DocumentList::print(std::ostream& out, bool verbose,
+ const std::string& indent) const
+{
+ out << "DocumentList(buffer: " << (void*) _buffer << ", size: "
+ << std::dec << _bufferSize << ", freeptr: " << (void*) _freePtr;
+ if (_buffer != 0) {
+ out << ", doccount: " << size();
+ if (_bufferSize >= sizeof(MetaEntry) * size() + sizeof(uint32_t)) {
+ for (uint32_t i=0, n=size(); i<n; ++i) {
+ out << "\n" << indent << " ";
+ const MetaEntry& entry(getMeta(i));
+ entry.print(out, indent + " ");
+ if (entry.headerPos + entry.headerLen > _bufferSize ||
+ entry.bodyPos + entry.bodyLen > _bufferSize) {
+ std::cerr << " Invalid entry. Aborting print.)";
+ return;
+ }
+ }
+ } else {
+ out << "\n" << indent << " Too small to contain these entries.";
+ }
+ }
+ uint32_t counter = 0;
+ for (DocumentList::const_iterator it = begin(); it != end(); ++it) {
+ out << "\n" << indent << " ";
+ if (++counter > 16) {
+ out << "...";
+ break;
+ }
+ it->print(out, verbose, indent + " ");
+ }
+ if (verbose && _bufferSize < 256) {
+ vespalib::string escaped;
+ vespalib::string tmp(_buffer, _bufferSize);
+ out << "\n" << indent << " content: "
+ << document::StringUtil::escape(tmp, escaped);
+ }
+ out << ")";
+}
+
+} // namespace vdslib
diff --git a/vdslib/src/vespa/vdslib/container/documentlist.h b/vdslib/src/vespa/vdslib/container/documentlist.h
new file mode 100644
index 00000000000..894195bcfee
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/container/documentlist.h
@@ -0,0 +1,250 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+/**
+ * @class vdslib::DocumentList
+ * @ingroup messageapi
+ *
+ * @brief A utility class for a buffer containing a list of documents.
+ *
+ * During visiting and subscriptions, one or more documents need to be sent
+ * to clients. Both documents added and removed. For performance reasons, we
+ * might need to bundle multiple entries together in a buffer, and for some
+ * extreme performance requirements, we might need to use shared memory to send
+ * this data to a process running on the same computer.
+ *
+ * The format is as follows. The first 4 bytes contain the number of meta
+ * entries in the block. After this, the list of meta entries is. Each entry
+ * is the memory representation of a MetaEntry object. After this list, a
+ * generic block with header and body blocks exist. The meta entry points to
+ * the data they use. Meta entry pointers are indexes starting from the start
+ * of the docblock.
+ *
+ */
+
+#pragma once
+
+#include <vespa/document/document.h>
+#include <vespa/document/repo/documenttyperepo.h>
+#include <vespa/vdslib/defs.h>
+
+namespace vdslib {
+
+class DocumentList : public document::Printable {
+public:
+
+ struct MetaEntry {
+ enum Flag {
+ REMOVE_ENTRY = 1,
+ BODY_STRIPPED = 2,
+ BODY_IN_HEADER = 4,
+ UPDATE_ENTRY = 8,
+ COMPRESSED = 16
+ };
+ Timestamp timestamp;
+ uint32_t headerPos;
+ uint32_t headerLen;
+ uint32_t bodyPos;
+ uint32_t bodyLen;
+ uint8_t flags;
+ uint8_t padding[7]; // In order to align equally in 32bit and 64bit
+
+ MetaEntry();
+ void print(std::ostream& out, const std::string& indent = "") const;
+ };
+
+ class Entry : public document::Printable {
+ private:
+ MetaEntry* _metaEntry;
+ char* _start;
+ uint32_t _entry;
+ const document::DocumentTypeRepo *_repo;
+
+ public:
+ Entry() : _metaEntry(0), _start(0), _entry(0), _repo(0) {}
+ Entry(char* start, uint32_t entry,
+ const document::DocumentTypeRepo &repo);
+
+ Entry(const Entry &rhs)
+ : document::Printable(rhs),
+ _metaEntry(rhs._metaEntry),
+ _start(rhs._start),
+ _entry(rhs._entry),
+ _repo(rhs._repo)
+ {
+ }
+
+ Entry& operator=(const Entry &rhs)
+ {
+ document::Printable::operator=(rhs);
+ _metaEntry = rhs._metaEntry;
+ _start = rhs._start;
+ _entry = rhs._entry;
+ _repo = rhs._repo;
+ return *this;
+ }
+
+ Entry next() const;
+
+ /** Entries in iterators gotten from DocumentList::end() are invalid. */
+ bool valid() const { return (_start != 0); }
+ bool isRemoveEntry() const
+ { return _metaEntry->flags & MetaEntry::REMOVE_ENTRY; }
+ bool isBodyStripped() const
+ { return _metaEntry->flags & MetaEntry::BODY_STRIPPED; }
+ bool hasBodyInHeader() const
+ { return _metaEntry->flags & MetaEntry::BODY_IN_HEADER; }
+ bool isUpdateEntry() const
+ { return _metaEntry->flags & MetaEntry::UPDATE_ENTRY; }
+ bool isCompressed() const
+ { return _metaEntry->flags & MetaEntry::COMPRESSED; }
+
+ uint8_t getFlags() const { return _metaEntry->flags; }
+ Timestamp getTimestamp() const { return _metaEntry->timestamp; }
+
+ void setTimestamp(Timestamp t) const { _metaEntry->timestamp = t; }
+
+ document::DocumentId getDocumentId() const;
+
+ /** Deserialize and get the document this entry points to. */
+ document::Document::UP getDocument(
+ const document::DocumentType *anticipatedType = 0) const;
+ document::Document::UP getHeader(
+ const document::DocumentType *anticipatedType = 0) const;
+ std::unique_ptr<document::DocumentUpdate> getUpdate() const;
+ bool getDocument(document::Document&, bool longLivedBuffer=false) const;
+ bool getHeader(document::Document&) const;
+ bool getUpdate(document::DocumentUpdate&) const;
+
+ typedef std::pair<char*, uint32_t> BufferPosition;
+ /**
+ * Get the raw header of the document; note that in case
+ * BODY_IN_HEADER is set, this also includes the body.
+ */
+ const BufferPosition getRawHeader() const;
+ /**
+ * Get the raw body of the document; note that in case BODY_IN_HEADER
+ * is set, this should not be used.
+ */
+ const BufferPosition getRawBody() const;
+ uint32_t getSerializedSize() const {
+ return _metaEntry->headerLen + _metaEntry->bodyLen
+ + sizeof(MetaEntry);
+ }
+
+ void print(std::ostream& out, bool verbose,
+ const std::string& indent) const;
+ bool operator==(const Entry& e) const
+ { return (_start == e._start && _entry == e._entry); }
+ };
+
+ class const_iterator {
+ Entry _entry;
+
+ public:
+ typedef std::input_iterator_tag iterator_category;
+ typedef Entry value_type;
+ typedef uint32_t difference_type;
+ typedef const Entry* pointer;
+ typedef const Entry& reference;
+
+ const_iterator(const Entry& e) : _entry(e) {}
+
+ const Entry& operator*() { return _entry; }
+ const Entry* operator->() { return &_entry; }
+ const_iterator& operator++(); // Prefix
+ const_iterator operator++(int); // Postfix
+ bool operator==(const const_iterator& it) const;
+ bool operator!=(const const_iterator& it) const;
+ };
+
+ /**
+ * Create a new documentlist, using the given buffer.
+ * @param keepexisting If set to true, assume buffer is already filled.
+ */
+ DocumentList(const document::DocumentTypeRepo::SP & repo, char* buffer, uint32_t bufferSize, bool keepexisting = false);
+
+ DocumentList(const DocumentList& source, char* buffer, uint32_t bufferSize);
+
+ virtual ~DocumentList();
+ DocumentList& operator=(const DocumentList &rhs);
+ DocumentList(const DocumentList &rhs);
+
+ /** return number of bytes free space (in the middle of the buffer) */
+ uint32_t countFree() const
+ {
+ return (_freePtr - _buffer) - sizeof(uint32_t)
+ - sizeof(MetaEntry) * size();
+ }
+
+ void clear() { docCount() = 0; _freePtr = _buffer + _bufferSize; }
+
+ uint32_t getBufferSize() const { return _bufferSize; }
+ char* getBuffer() { return _buffer; }
+ const char* getBuffer() const { return _buffer; }
+
+ const_iterator begin() const {
+ return const_iterator(
+ Entry((_freePtr < _buffer + _bufferSize ? _buffer : 0), 0,
+ *_repo));
+ }
+ const_iterator end() const { return const_iterator(Entry()); }
+ uint32_t size() const { return (_buffer == 0 ? 0 : docCount()); }
+
+ /** compute minimum number of bytes needed to hold the current documentlist */
+ uint64_t spaceNeeded() const {
+ uint32_t n = docCount();
+ uint64_t need = sizeof(uint32_t);
+ for (uint32_t i = 0; i < n; ++i) {
+ const MetaEntry& entry(getMeta(i));
+ need += sizeof(MetaEntry) + entry.headerLen + entry.bodyLen;
+ }
+ return need;
+ }
+
+ void checkConsistency(bool do_memset = false);
+
+ /** fill any free space in the buffer with FF bytes */
+ void fillFreespace() {
+ if (_buffer == 0) return;
+ checkConsistency(true);
+ char *startOfFree = _buffer + sizeof(uint32_t) + docCount() * sizeof(MetaEntry);
+ assert(startOfFree < _freePtr);
+ memset(startOfFree, 0xff, _freePtr - startOfFree);
+ }
+
+ void print(std::ostream& out, bool verbose,
+ const std::string& indent) const;
+
+ const document::DocumentTypeRepo::SP & getTypeRepo() const { return _repo; }
+
+protected:
+ char *_buffer;
+ uint32_t _bufferSize;
+ uint32_t _wasted;
+ char *_freePtr;
+
+ uint32_t docCount() const { return *reinterpret_cast<uint32_t*>(_buffer); }
+
+ uint32_t& docCount() { return *reinterpret_cast<uint32_t*>(_buffer); }
+ const MetaEntry& getMeta(uint32_t index) const
+ {
+ return *reinterpret_cast<MetaEntry*>(_buffer + sizeof(uint32_t)
+ + index * sizeof(MetaEntry));
+ }
+ MetaEntry& getMeta(uint32_t index)
+ {
+ return *reinterpret_cast<MetaEntry*>(_buffer + sizeof(uint32_t)
+ + index * sizeof(MetaEntry));
+ }
+private:
+ void init(bool keepExisting);
+ document::DocumentTypeRepo::SP _repo;
+};
+
+inline std::ostream& operator<<(std::ostream& out, const DocumentList::MetaEntry& e)
+{
+ e.print(out);
+ return out;
+}
+
+}
+
diff --git a/vdslib/src/vespa/vdslib/container/documentsummary.cpp b/vdslib/src/vespa/vdslib/container/documentsummary.cpp
new file mode 100644
index 00000000000..e1bd73a09de
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/container/documentsummary.cpp
@@ -0,0 +1,88 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#include <vespa/fastos/fastos.h>
+#include "documentsummary.h"
+
+namespace vdslib {
+
+DocumentSummary::DocumentSummary() :
+ _summaryBuffer(),
+ _summary(),
+ _summarySize(0)
+{
+ _summaryBuffer.reset(new vespalib::MallocPtr(4096));
+}
+
+DocumentSummary::DocumentSummary(document::ByteBuffer& buf) :
+ _summaryBuffer(),
+ _summary(),
+ _summarySize(0)
+{
+ deserialize(buf);
+}
+
+void DocumentSummary::deserialize(document::ByteBuffer& buf)
+{
+ int32_t tmp;
+ buf.getIntNetwork(tmp); // Just get dummy 4 byte field, to avoid handling different versions.
+ uint32_t numResults(0);
+ buf.getIntNetwork(tmp); numResults = tmp;
+ _summary.resize(numResults);
+ if (numResults > 0) {
+ buf.getIntNetwork(tmp); _summarySize = tmp;
+ _summaryBuffer.reset(new vespalib::MallocPtr(getSummarySize()));
+ buf.getBytes(_summaryBuffer->str(), _summaryBuffer->size());
+
+ const char * summarybp(_summaryBuffer->c_str());
+ for (size_t n(0), p(0), m(_summary.size()); n < m; n++) {
+ uint32_t sz(0);
+ buf.getIntNetwork(tmp); sz = tmp;
+ size_t oldP(p);
+ while (summarybp[p++]) { }
+ _summary[n] = Summary(oldP, p, sz);
+ p += sz;
+ }
+ }
+}
+
+void DocumentSummary::serialize(document::ByteBuffer& buf) const
+{
+ buf.putIntNetwork(0); // Just serialize dummy 4 byte field, to avoid versioning.
+ buf.putIntNetwork(_summary.size());
+ if ( ! _summary.empty() ) {
+ buf.putIntNetwork(getSummarySize());
+ for (size_t i(0), m(_summary.size()); i < m; i++) {
+ Summary s(_summary[i]);
+ buf.putBytes(s.getDocId(_summaryBuffer->c_str()), s.getTotalSize());
+ }
+ for (size_t i(0), m(_summary.size()); i < m; i++) {
+ buf.putIntNetwork(_summary[i].getSummarySize());
+ }
+ }
+}
+
+uint32_t DocumentSummary::getSerializedSize() const
+{
+ return (! _summary.empty()) ? 4*(3 + getSummaryCount()) + getSummarySize() : 8;
+}
+
+void DocumentSummary::addSummary(const char *docId, const void * buf, size_t sz)
+{
+ const size_t idSize = strlen(docId) + 1;
+ Summary s(getSummarySize(), getSummarySize() + idSize, sz);
+ _summary.push_back(s);
+ const size_t end(getSummarySize() + idSize + sz);
+ if (end > _summaryBuffer->size()) {
+ _summaryBuffer->realloc(end*2);
+ }
+ memcpy(_summaryBuffer->str() + getSummarySize(), docId, idSize);
+ memcpy(_summaryBuffer->str() + getSummarySize()+idSize, buf, sz);
+ _summarySize = end;
+}
+
+void DocumentSummary::sort()
+{
+ std::sort(_summary.begin(), _summary.end(), Compare(_summaryBuffer->c_str()));
+}
+
+}
+
diff --git a/vdslib/src/vespa/vdslib/container/documentsummary.h b/vdslib/src/vespa/vdslib/container/documentsummary.h
new file mode 100644
index 00000000000..2b97a90ae1d
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/container/documentsummary.h
@@ -0,0 +1,63 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#pragma once
+
+#include <vespa/vespalib/util/memory.h>
+#include <vespa/document/util/bytebuffer.h>
+#include <vector>
+
+namespace vdslib {
+
+class DocumentSummary {
+public:
+ DocumentSummary();
+
+ /**
+ * Constructs a new message from a byte buffer.
+ *
+ * @param buf A byte buffer that contains a serialized message.
+ */
+ DocumentSummary(document::ByteBuffer& buf);
+
+ size_t getSummaryCount() const { return _summary.size(); }
+ void getSummary(size_t hitNo, const char * & docId, const void * & buf, size_t & sz) {
+ docId = _summary[hitNo].getDocId(_summaryBuffer->c_str());
+ buf = _summary[hitNo].getSummary(_summaryBuffer->c_str(), sz);
+ }
+ void addSummary(const char * docId, const void * buf, size_t sz);
+ void sort();
+
+ void deserialize(document::ByteBuffer& buf);
+ void serialize(document::ByteBuffer& buf) const;
+ uint32_t getSerializedSize() const;
+private:
+ class Summary {
+ public:
+ Summary() : _docIdOffset(0), _summaryOffset(0), _summaryLen(0) { }
+ Summary(uint32_t docIdOffset, uint32_t summaryOffset, uint32_t summaryLen) : _docIdOffset(docIdOffset), _summaryOffset(summaryOffset), _summaryLen(summaryLen) { }
+ const char * getDocId(const char * base) const { return base + _docIdOffset; }
+ const void * getSummary(const char * base, size_t & sz) const { sz = _summaryLen; return base + _summaryOffset; }
+ size_t getSummarySize() const { return _summaryLen; }
+ size_t getTotalSize() const { return _summaryOffset - _docIdOffset + _summaryLen; }
+ private:
+ uint32_t _docIdOffset;
+ uint32_t _summaryOffset;
+ uint32_t _summaryLen;
+ };
+ class Compare : public std::binary_function<Summary, Summary, bool> {
+ private:
+ const char * _buffer;
+ public:
+ Compare(const char * buffer) : _buffer(buffer) { }
+ bool operator() (const Summary & x, const Summary & y) const {
+ return strcmp(x.getDocId(_buffer), y.getDocId(_buffer)) < 0;
+ }
+ };
+ size_t getSummarySize() const { return _summarySize; }
+ typedef std::shared_ptr<vespalib::MallocPtr> DocBuffer;
+ DocBuffer _summaryBuffer; // Raw zero-terminated documentids in rank order.
+ std::vector<Summary> _summary; // Constructed vector containing offset of document in buffer.
+ size_t _summarySize;
+};
+
+}
+
diff --git a/vdslib/src/vespa/vdslib/container/dummycppfile.cpp b/vdslib/src/vespa/vdslib/container/dummycppfile.cpp
new file mode 100644
index 00000000000..45aaeddf702
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/container/dummycppfile.cpp
@@ -0,0 +1,4 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+ // This file exist because make make can't install headers from a directory
+ // without having a cpp file to build..
diff --git a/vdslib/src/vespa/vdslib/container/lruorder.h b/vdslib/src/vespa/vdslib/container/lruorder.h
new file mode 100644
index 00000000000..026b8189ae0
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/container/lruorder.h
@@ -0,0 +1,161 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+/**
+ * Keep an LRU order of a given size. This is a utility class for adding a
+ * secondary order to some other container.
+ */
+#pragma once
+
+#include <vespa/document/util/printable.h>
+#include <vector>
+#include <vespa/vespalib/util/exceptions.h>
+
+namespace storage {
+namespace lib {
+
+template<typename Value, typename RemoveFunctor, bool staticSize = true>
+class LruOrder : public document::Printable {
+public:
+ class EntryRef {
+ uint32_t _entryIndex;
+ public:
+ EntryRef() : _entryIndex(0xffffffffu) {}
+ EntryRef(uint32_t index) : _entryIndex(index) {}
+ friend class LruOrder;
+ };
+
+private:
+ struct Entry {
+ Value _value;
+ bool _inUse;
+ uint32_t _previous;
+ uint32_t _next;
+
+ public:
+ Entry() : _value(), _inUse(false),
+ _previous(0xffffffffu), _next(0xffffffffu) {}
+ };
+
+ RemoveFunctor& _removeFunctor;
+ std::vector<Entry> _entries;
+
+ Entry& first() { return _entries[0]; }
+ Entry& last() { return _entries[1]; }
+ Entry& previous(Entry& e) { return _entries[e._previous]; }
+ Entry& next(Entry& e) { return _entries[e._next]; }
+ uint32_t getIndex(Entry& e) { return next(e)._previous; }
+ Entry& get(const EntryRef& e) { return _entries[e._entryIndex]; }
+
+public:
+ LruOrder(uint32_t size, RemoveFunctor& rf)
+ : _removeFunctor(rf), _entries(size + 2)
+ {
+ initializeOrderVector();
+ }
+
+ /**
+ * Clear all entries. Invalidates all previously returned entry references.
+ */
+ void clear() {
+ for (uint32_t i=2, n=_entries.size(); i<n; ++i) {
+ _entries[i]._inUse = false;
+ }
+ }
+
+ /**
+ * Adds a value to the order index. Return a reference to an object that
+ * can be used to refer to the value.
+ */
+ EntryRef add(const Value& k) {
+ Entry& e(previous(last()));
+ if (e._inUse) {
+ _removeFunctor.removedFromOrder(e._value);
+ }
+ e._value = k;
+ e._inUse = true;
+ moveToStart(EntryRef(getIndex(e)));
+ return EntryRef(getIndex(e));
+ }
+
+ void remove(EntryRef ref) {
+ uint32_t index(ref._entryIndex);
+ Entry& e(get(ref));
+ e._inUse = false;
+ // Remove entry from current place in sequence
+ next(e)._previous = e._previous;
+ previous(e)._next = e._next;
+ // Make entry fit being at end.
+ e._next = 1;
+ e._previous = last()._previous;
+ // Insert at end
+ previous(last())._next = index;
+ last()._previous = index;
+ }
+
+ /**
+ * Move given entry to the start of the order.
+ */
+ void moveToStart(EntryRef ref) {
+ uint32_t index(ref._entryIndex);
+ Entry& e(get(ref));
+ // Remove entry from current place in sequence
+ next(e)._previous = e._previous;
+ previous(e)._next = e._next;
+ // Make entry fit being at start.
+ e._next = first()._next;
+ e._previous = 0;
+ // Insert at beginning
+ next(first())._previous = index;
+ first()._next = index;
+ }
+
+private:
+ void initializeOrderVector() {
+ if (_entries.size() < 1 || _entries.size() > 0xffffffffu - 3) {
+ throw vespalib::IllegalArgumentException(
+ "LruOrder size needs to be between 1 and 3 below max "
+ "uint32_t value, as it needs to reserve 3 values.",
+ VESPA_STRLOC);
+ }
+ _entries[0]._next = 2; // First token
+ _entries[1]._previous = _entries.size() - 1; // Last token
+ for (uint32_t i=2, n=_entries.size(); i<n; ++i) {
+ _entries[i]._next = i+1;
+ _entries[i]._previous = i-1;
+ }
+ // Make first and last actual elements point to first and last.
+ _entries[2]._previous = 0;
+ _entries[_entries.size() - 1]._next = 1;
+ }
+
+ void print(std::ostream& out, bool verbose, const std::string& indent) const
+ {
+ if (verbose) {
+ out << "LruOrder(" << (staticSize ? "static" : "dynamic") << "size "
+ << (_entries.size() - 2) << ") {";
+ for (uint32_t i=0; i<_entries.size(); ++i) {
+ const Entry& e(_entries[i]);
+ out << "\n" << indent << " " << i << ": <- " << e._previous
+ << " " << e._next << " -> ";
+ if (e._inUse) {
+ out << "(" << e._value << ")";
+ }
+ }
+ out << "\n" << indent << "}";
+ } else {
+ out << "[";
+ const Entry* e = &_entries[_entries[0]._next];
+ if (e->_inUse) {
+ out << e->_value;
+ }
+ while (true) {
+ e = &_entries[e->_next];
+ if (!e->_inUse) break;
+ out << ", " << e->_value;
+ }
+ out << "]";
+ }
+ }
+};
+
+} // lib
+} // storage
diff --git a/vdslib/src/vespa/vdslib/container/mutabledocumentlist.cpp b/vdslib/src/vespa/vdslib/container/mutabledocumentlist.cpp
new file mode 100644
index 00000000000..6654cbad87f
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/container/mutabledocumentlist.cpp
@@ -0,0 +1,223 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#include <vespa/fastos/fastos.h>
+#include <vespa/vdslib/container/mutabledocumentlist.h>
+
+#include <vespa/log/log.h>
+#include <vespa/vespalib/objects/nbostream.h>
+
+using vespalib::nbostream;
+
+LOG_SETUP(".vdslib.container.mutabledocumentlist");
+
+namespace vdslib {
+MutableDocumentList::MutableDocumentList(const document::DocumentTypeRepo::SP & repo, char* buffer, uint32_t bufferSize, bool keepexisting)
+ : DocumentList(repo, buffer, bufferSize, keepexisting)
+{
+}
+
+MutableDocumentList::MutableDocumentList(const DocumentList& source,
+ char* buffer,
+ uint32_t bufferSize)
+ : DocumentList(source, buffer, bufferSize)
+{
+}
+
+bool
+MutableDocumentList::addOperationList(const OperationList& opl)
+{
+ for(uint32_t i=0; i < opl.getOperationList().size(); i++){
+ switch(opl.getOperationList()[i].opt) {
+ case OperationList::Operation::PUT:
+ if (!addPut(*opl.getOperationList()[i].document, 0)) return false;
+ break;
+ case OperationList::Operation::UPDATE:
+ if (!addUpdate(*opl.getOperationList()[i].documentUpdate, 0)) return false;
+ break;
+ case OperationList::Operation::REMOVE:
+ if (!addRemove(opl.getOperationList()[i].docId,0)) return false;
+ break;
+ }
+ }
+ checkConsistency();
+ return true;
+}
+
+bool
+MutableDocumentList::addPut(const document::Document& doc, Timestamp ts,
+ bool addBody)
+{
+ uint32_t freePos = _freePtr - _buffer;
+
+ nbostream stream;
+ doc.serializeHeader(stream);
+ uint32_t headerSize = stream.size();
+
+ if (addBody) {
+ doc.serializeBody(stream);
+ }
+
+ uint32_t totalSize = stream.size();
+ uint32_t bodySize = totalSize - headerSize;
+
+ if (countFree() < totalSize + sizeof(MetaEntry)) {
+ return false;
+ }
+
+ MetaEntry& entry(getMeta(docCount()));
+ entry.timestamp = ts;
+ entry.headerPos = freePos - totalSize;
+ entry.headerLen = headerSize;
+ entry.bodyPos = bodySize ? (freePos - bodySize) : 0;
+ entry.bodyLen = bodySize;
+ entry.flags = 0;
+
+ if (doc.getType().getFieldsType().getCompressionConfig().type
+ != document::CompressionConfig::NONE)
+ {
+ entry.flags |= MetaEntry::COMPRESSED;
+ }
+
+ document::ByteBuffer buffer(_freePtr - totalSize, totalSize);
+
+ buffer.putBytes(stream.peek(), stream.size());
+ if (!addBody) {
+ entry.flags |= MetaEntry::BODY_STRIPPED;
+ }
+
+ // Here we're sure we've completed writing doc, and can update internal
+ // info to commit the write.
+ _freePtr -= totalSize;
+ ++docCount();
+ checkConsistency();
+ return true;
+}
+
+bool
+MutableDocumentList::addUpdate(const document::DocumentUpdate& update,
+ Timestamp ts)
+{
+ vespalib::nbostream os;
+ update.serialize42(os);
+ uint32_t updsize = os.size();
+
+ if (countFree() - sizeof(MetaEntry) < updsize) {
+ return false;
+ }
+
+ MetaEntry& entry(getMeta(docCount()));
+ entry.timestamp = ts;
+ entry.headerPos = (_freePtr - _buffer - updsize);
+ entry.headerLen = updsize;
+ entry.bodyPos = 0;
+ entry.bodyLen = 0;
+ entry.flags = 0;
+
+ document::ByteBuffer buffer(_freePtr - updsize, updsize);
+
+ buffer.putBytes(os.c_str(), os.size());
+ entry.flags |= MetaEntry::UPDATE_ENTRY;
+
+ // Here we're sure we've completed writing update, and can update internal
+ // info to commit the write.
+ _freePtr -= updsize;
+ ++docCount();
+ checkConsistency();
+ return true;
+}
+
+
+bool
+MutableDocumentList::addRemove(const document::DocumentId& docId, Timestamp ts)
+{
+ // Creating a document by fetching the first document type declared
+
+ const document::DataType *type(document::DataType::DOCUMENT);
+ if (docId.hasDocType()) {
+ type = getTypeRepo()->getDocumentType(docId.getDocType());
+ }
+ document::Document doc(*type, docId);
+ nbostream stream;
+ doc.serializeHeader(stream);
+ uint32_t ssize = stream.size();
+ if (countFree() < ssize + sizeof(MetaEntry)) {
+ return false;
+ }
+
+ MetaEntry& entry(getMeta(docCount()));
+ entry.timestamp = ts;
+ entry.headerPos = (_freePtr - _buffer - ssize);
+ entry.headerLen = ssize;
+ entry.bodyPos = 0;
+ entry.bodyLen = 0;
+ entry.flags = MetaEntry::REMOVE_ENTRY;
+ document::ByteBuffer buffer(_freePtr - ssize, ssize);
+ doc.serializeHeader(buffer);
+ // Here we're sure we've completed writing doc, and can update internal
+ // info to commit the remove.
+ _freePtr -= ssize;
+ ++docCount();
+ //printState("Post removing");
+ checkConsistency();
+ return true;
+}
+
+
+bool
+MutableDocumentList::addEntry(const DocumentList::Entry& inEntry)
+{
+ return addEntry(inEntry, inEntry.getTimestamp());
+}
+
+bool
+MutableDocumentList::addEntry(const DocumentList::Entry& inEntry, Timestamp ts)
+{
+ if (countFree() < inEntry.getSerializedSize()) {
+ return false;
+ }
+
+ MetaEntry& entry(getMeta(docCount()));
+ entry.timestamp = ts;
+ entry.headerPos = 0;
+ entry.headerLen = 0;
+ entry.bodyPos = 0;
+ entry.bodyLen = 0;
+ entry.flags = inEntry.getFlags();
+
+ if ((inEntry.getFlags() & DocumentList::MetaEntry::BODY_IN_HEADER) ||
+ (inEntry.getFlags() & DocumentList::MetaEntry::BODY_STRIPPED))
+ {
+ DocumentList::Entry::BufferPosition header = inEntry.getRawHeader();
+ document::ByteBuffer buffer(_freePtr - header.second, header.second);
+
+ entry.headerPos = (_freePtr - _buffer - header.second);
+ entry.headerLen = header.second;
+ entry.bodyPos = 0;
+ entry.bodyLen = 0;
+ buffer.putBytes(header.first, header.second);
+
+ // Here we're sure we've completed writing doc, and can update internal
+ // info to commit the write.
+ _freePtr -= header.second;
+ } else {
+ DocumentList::Entry::BufferPosition header = inEntry.getRawHeader();
+ DocumentList::Entry::BufferPosition body = inEntry.getRawBody();
+ document::ByteBuffer buffer(_freePtr - (header.second + body.second), (header.second + body.second));
+
+ entry.headerPos = (_freePtr - _buffer - header.second);
+ entry.headerLen = header.second;
+ entry.bodyPos = (_freePtr - _buffer - header.second - body.second);
+ entry.bodyLen = body.second;
+ buffer.putBytes(body.first, body.second);
+ buffer.putBytes(header.first, header.second);
+
+ // Here we're sure we've completed writing doc, and can update internal
+ // info to commit the write.
+ _freePtr -= (header.second + body.second);
+ }
+
+ ++docCount();
+ checkConsistency();
+ return true;
+}
+
+} // vdslib
diff --git a/vdslib/src/vespa/vdslib/container/mutabledocumentlist.h b/vdslib/src/vespa/vdslib/container/mutabledocumentlist.h
new file mode 100644
index 00000000000..99d29565d42
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/container/mutabledocumentlist.h
@@ -0,0 +1,46 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+/**
+ * @class storage::api::MutableDocumentList
+ * @ingroup messageapi
+ *
+ * @brief A utility class for a buffer containing a list of documents.
+ *
+ * When writing to the docblock, it will typically be filled up from the end
+ * and forwards, until the free gap between the meta entry list and the data
+ * it uses, is so small that no more entry fits.
+ *
+ * @version $Id$
+ */
+
+#pragma once
+
+#include <vespa/vdslib/container/documentlist.h>
+#include <vespa/vdslib/container/operationlist.h>
+
+namespace vdslib {
+
+class MutableDocumentList : public DocumentList {
+public:
+ /**
+ * Create a new docblock, using the given buffer.
+ * @param keepexisting If set to true, assume buffer is already filled.
+ */
+ MutableDocumentList(const document::DocumentTypeRepo::SP & repo, char* buffer, uint32_t bufferSize, bool keepexisting = false);
+
+ MutableDocumentList(const DocumentList& source, char* buffer, uint32_t bufferSize);
+
+ // Want to take const pointers to docs here, but can't since we need to
+ // call serializeHeader/Body.. Grmpf..
+
+ /** Returns false if no more space in docblock. (Entry not added) */
+ bool addPut(const document::Document&, Timestamp = 0, bool addBody = true);
+ /** Returns false if no more space in docblock. (Entry not added) */
+ bool addRemove(const document::DocumentId& docId, Timestamp = 0);
+ bool addEntry(const DocumentList::Entry& inEntry);
+ bool addEntry(const DocumentList::Entry& inEntry, Timestamp ts);
+ bool addOperationList(const OperationList& list);
+ bool addUpdate(const document::DocumentUpdate&, Timestamp = 0);
+};
+
+} // vdslib
+
diff --git a/vdslib/src/vespa/vdslib/container/operationlist.cpp b/vdslib/src/vespa/vdslib/container/operationlist.cpp
new file mode 100644
index 00000000000..5417211a0f0
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/container/operationlist.cpp
@@ -0,0 +1,43 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#include <vespa/fastos/fastos.h>
+#include <vespa/vdslib/container/operationlist.h>
+
+#include <vespa/vdslib/container/documentlist.h>
+
+namespace vdslib {
+
+int OperationList::getRequiredBufferSize() const {
+ int bufferSize = 4;
+
+ vespalib::nbostream stream;
+
+ // Creating a document by fetching the first document type declared
+ for(uint32_t i=0; i < _operations.size();i++){
+ stream.clear();
+ switch(_operations[i].opt) {
+ case OperationList::Operation::REMOVE:
+ {
+ document::Document doc(*document::DataType::DOCUMENT,
+ _operations[i].docId);
+ doc.serializeHeader(stream);
+ break;
+ }
+ case OperationList::Operation::PUT:
+ {
+ _operations[i].document->serializeHeader(stream);
+ _operations[i].document->serializeBody(stream);
+ break;
+ }
+ case OperationList::Operation::UPDATE:
+ {
+ _operations[i].documentUpdate->serialize42(stream);
+ break;
+ }
+ }
+ bufferSize += stream.size();
+ }
+
+ return bufferSize + (_operations.size() * sizeof(DocumentList::MetaEntry));
+}
+
+} // vdslib
diff --git a/vdslib/src/vespa/vdslib/container/operationlist.h b/vdslib/src/vespa/vdslib/container/operationlist.h
new file mode 100644
index 00000000000..609ac9963d8
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/container/operationlist.h
@@ -0,0 +1,81 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#pragma once
+
+#include <vespa/document/fieldvalue/document.h>
+
+namespace document { class DocumentUpdate; }
+
+namespace vdslib {
+
+class OperationList{
+public:
+
+ struct Operation{
+ enum OpType{
+ PUT=0,
+ UPDATE=1,
+ REMOVE=2
+ };
+
+ Operation(document::DocumentId dId)
+ : docId(dId),
+ opt(REMOVE)
+ {
+ }
+
+ Operation(std::shared_ptr<document::Document> doc)
+ : document(doc),
+ opt(PUT)
+ {
+ }
+
+ Operation(std::shared_ptr<document::DocumentUpdate> doc)
+ : documentUpdate(doc),
+ opt(UPDATE)
+ {
+ }
+
+ document::DocumentId docId;
+ std::shared_ptr<document::Document> document;
+ std::shared_ptr<document::DocumentUpdate> documentUpdate;
+ OpType opt;
+ };
+
+ void addPut(std::shared_ptr<document::Document> doc) {
+ _operations.push_back(Operation(doc));
+ }
+
+ void addUpdate(std::shared_ptr<document::DocumentUpdate> docUpdate) {
+ _operations.push_back(Operation(docUpdate));
+ }
+
+ void addRemove(document::DocumentId docId) {
+ _operations.push_back(Operation(docId));
+ }
+
+ int getRequiredBufferSize() const;
+
+ const std::vector<Operation>& getOperationList() const{
+ return _operations;
+ }
+
+ // Deprecated functions. This list used to const cast and ruin source
+ // objects in copy constructor. Keeping deprecated functions to avoid
+ // breaking factory now, as they still work fine. Just code bloat.
+
+ void addPut(std::unique_ptr<document::Document> doc) {
+ _operations.push_back(
+ Operation(std::shared_ptr<document::Document>(std::move(doc))));
+ }
+
+ void addUpdate(std::unique_ptr<document::DocumentUpdate> docUpdate) {
+ _operations.push_back(
+ Operation(std::shared_ptr<document::DocumentUpdate>(std::move(docUpdate))));
+ }
+
+private:
+ std::vector<Operation> _operations;
+
+};
+}
+
diff --git a/vdslib/src/vespa/vdslib/container/parameters.cpp b/vdslib/src/vespa/vdslib/container/parameters.cpp
new file mode 100644
index 00000000000..83907ed6960
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/container/parameters.cpp
@@ -0,0 +1,152 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/fastos/fastos.h>
+#include <vespa/vdslib/container/parameters.h>
+
+#include <sstream>
+
+using namespace vdslib;
+
+Parameters::~Parameters()
+{
+}
+
+size_t Parameters::getSerializedSize() const
+{
+ size_t mysize = sizeof(int32_t);
+ for (const auto & entry : _parameters) {
+ mysize += entry.first.size() + 4 + 4 + entry.second.size();
+ }
+ return mysize;
+}
+
+void Parameters::onSerialize(document::ByteBuffer& buffer) const
+{
+ buffer.putIntNetwork(_parameters.size());
+ for (const auto & entry : _parameters) {
+ buffer.putIntNetwork(entry.first.size());
+ buffer.putBytes(entry.first.c_str(), entry.first.size());
+ buffer.putIntNetwork(entry.second.size());
+ buffer.putBytes(entry.second.c_str(), entry.second.size());
+ }
+}
+
+void Parameters::onDeserialize(const document::DocumentTypeRepo &repo,
+ document::ByteBuffer& buffer)
+{
+ (void) repo;
+ _parameters.clear();
+ int32_t mysize;
+ buffer.getIntNetwork(mysize);
+ for (int i=0; i<mysize; i++) {
+ int32_t keylen = 0;
+ buffer.getIntNetwork(keylen);
+ vespalib::stringref key(buffer.getBufferAtPos(), keylen);
+ buffer.incPos(keylen);
+ int32_t sz(0);
+ buffer.getIntNetwork(sz);
+ _parameters[key] = Value(buffer.getBufferAtPos(), sz);
+ buffer.incPos(sz);
+ }
+}
+
+void
+Parameters::printXml(document::XmlOutputStream& xos) const
+{
+ using namespace document;
+ xos << XmlTag("parameters");
+ for (const auto & entry : _parameters) {
+ xos << XmlTag("item")
+ << XmlTag("name") << entry.first << XmlEndTag()
+ << XmlTag("value") << entry.second << XmlEndTag()
+ << XmlEndTag();
+ }
+ xos << XmlEndTag();
+}
+
+/*
+void
+Parameters::deserializeXml(const document::XmlElement & xml)
+{
+ ParametersMap params;
+ for(document::XmlElement::ElementList::const_iterator it = xml.elements().begin(), mt = xml.elements().end(); it != mt; it++) {
+ const document::XmlElement & elem = *it;
+ assert( elem.elements().size() == 2);
+
+ const document::XmlElement & name = (*it).elements()[0];
+ const document::XmlElement & value = (*it).elements()[1];
+ params[name.value()] = Value(value.value().c_str(), value.value().size());
+ }
+ _parameters.swap(params);
+}
+*/
+
+bool
+Parameters::operator==(const Parameters &other) const
+{
+ if (size() != other.size()) {
+ return false;
+ }
+
+ for (ParametersMap::const_iterator a(_parameters.begin()), b(other._parameters.begin()), am(_parameters.begin()); (a != am); ++a, ++b) {
+ if ((a->first != b->first)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+Parameters* Parameters::clone() const
+{
+ return new Parameters(*this);
+}
+
+vespalib::stringref Parameters::get(const vespalib::stringref& id, const vespalib::stringref& def) const
+{
+ ParametersMap::const_iterator it = _parameters.find(id);
+ if (it == _parameters.end()) return def;
+ return it->second;
+}
+
+bool Parameters::get(const KeyT & id, ValueRef & v ) const
+{
+ ParametersMap::const_iterator it = _parameters.find(id);
+ if (it == _parameters.end()) return false;
+ v = ValueRef(it->second.c_str(), it->second.size());
+ return true;
+}
+
+void Parameters::print(std::ostream& out, bool verbose, const std::string& indent) const
+{
+ out << "Parameters(";
+ if (!verbose) {
+ out << _parameters.size() << " values";
+ } else {
+ for (const auto & entry : _parameters) {
+ bool isPrintable(true);
+ for (size_t i(0), m(entry.second.size()); isPrintable && (i < m); i++) {
+ isPrintable = isprint(entry.second[i]);
+ }
+ out << "\n" << indent << " " << entry.first << " = ";
+ if (!entry.second.empty() && isPrintable && (entry.second[entry.second.size()-1] == 0)) {
+ out << entry.second.c_str();
+ } else {
+ out << vespalib::HexDump(entry.second.c_str(), entry.second.size());
+ }
+ }
+ }
+ out << ")";
+}
+
+std::string Parameters::toString() const
+{
+ vespalib::string ret;
+ for (const auto & entry : _parameters) {
+ ret += entry.first;
+ ret += '=';
+ ret += entry.second;
+ ret += '|';
+ }
+ return ret;
+}
diff --git a/vdslib/src/vespa/vdslib/container/parameters.h b/vdslib/src/vespa/vdslib/container/parameters.h
new file mode 100644
index 00000000000..b687e8aa1b0
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/container/parameters.h
@@ -0,0 +1,110 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+/**
+ * @class storage::api::Parameters
+ * @ingroup messageapi
+ *
+ * @brief A serializable way of setting parameters.
+ *
+ * Utility class for passing sets of name-value parameter pairs around.
+ *
+ * @author Fledsbo, HÃ¥kon Humberset
+ * @date 2004-03-24
+ * @version $Id$
+ */
+
+#pragma once
+
+#include <vespa/document/util/serializable.h>
+#include <vespa/document/util/xmlserializable.h>
+#include <vespa/vespalib/stllike/asciistream.h>
+#include <vespa/vespalib/stllike/hash_map.h>
+
+namespace vdslib {
+
+class Parameters : public document::Deserializable,
+ public document::XmlSerializable {
+public:
+ typedef vespalib::stringref KeyT;
+ class Value : public vespalib::string
+ {
+ public:
+ Value() { }
+ Value(const vespalib::stringref & s) : vespalib::string(s) { }
+ Value(const vespalib::string & s) : vespalib::string(s) { }
+ Value(const void *v, size_t sz) : vespalib::string(v, sz) { }
+ size_t length() const { return size() - 1; }
+ };
+ typedef vespalib::stringref ValueRef;
+ typedef vespalib::hash_map<vespalib::string, Value> ParametersMap;
+private:
+ ParametersMap _parameters;
+
+ void onSerialize(document::ByteBuffer& buffer) const;
+ void onDeserialize(const document::DocumentTypeRepo &repo,
+ document::ByteBuffer& buffer);
+ void printXml(document::XmlOutputStream& xos) const;
+
+public:
+ Parameters() : _parameters() {}
+ Parameters(const document::DocumentTypeRepo &repo,
+ document::ByteBuffer& buffer)
+ : _parameters() { deserialize(repo, buffer); }
+ virtual ~Parameters();
+
+ bool operator==(const Parameters &other) const;
+
+ Parameters* clone() const;
+
+ size_t getSerializedSize() const;
+
+ bool hasValue(const KeyT & id) const { return (_parameters.find(id) != _parameters.end()); }
+ unsigned int size() const { return _parameters.size(); }
+ bool get(const KeyT & id, ValueRef & v ) const;
+ void set(const KeyT & id, const void * v, size_t sz) { _parameters[id] = Value(v, sz); }
+
+ void print(std::ostream& out, bool verbose, const std::string& indent) const;
+
+ // Disallow
+ ParametersMap::const_iterator begin() const { return _parameters.begin(); }
+ ParametersMap::const_iterator end() const { return _parameters.end(); }
+ /// Convenience from earlier use.
+ void set(const KeyT & id, const vespalib::stringref & value) { _parameters[id] = Value(value.c_str(), value.size()); }
+ vespalib::stringref get(const KeyT & id, const vespalib::stringref & def = "") const;
+ /**
+ * Set the value identified by the id given. This requires the type to be
+ * convertible by stringstreams.
+ *
+ * @param id The value to get.
+ * @param t The value to save. Will be converted to a string.
+ */
+ template<typename T>
+ void set(const KeyT & id, const T& t) {
+ vespalib::asciistream ost;
+ ost << t;
+ _parameters[id] = ost.str();
+ }
+
+ /**
+ * Get the value identified by the id given, as the same type as the default
+ * value given. This requires the type to be convertible by stringstreams.
+ *
+ * @param id The value to get.
+ * @param def The value to return if the value does not exist.
+ * @return The value represented as the same type as the default given, or
+ * the default itself if value did not exist.
+ */
+ template<typename T>
+ T get(const KeyT & id, const T& def) const {
+ vespalib::stringref ref;
+ if (!get(id, ref)) return def;
+ vespalib::asciistream ist(ref);
+ T t;
+ ist >> t;
+ return t;
+ }
+
+ std::string toString() const;
+};
+
+} // vdslib
+
diff --git a/vdslib/src/vespa/vdslib/container/searchresult.cpp b/vdslib/src/vespa/vdslib/container/searchresult.cpp
new file mode 100644
index 00000000000..6410fba020f
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/container/searchresult.cpp
@@ -0,0 +1,213 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#include <vespa/fastos/fastos.h>
+#include "searchresult.h"
+
+namespace vdslib {
+
+void AggregatorList::add(size_t id, const vespalib::MallocPtr & aggrBlob)
+{
+ insert(value_type(id, aggrBlob));
+}
+
+void AggregatorList::deserialize(document::ByteBuffer & buf)
+{
+ int32_t tmp(0);
+ buf.getIntNetwork(tmp);
+ for (size_t i(tmp); i; i--) {
+ buf.getIntNetwork(tmp);
+ size_t id(tmp);
+ buf.getIntNetwork(tmp);
+ size_t sz(tmp);
+ vespalib::MallocPtr aggr(sz);
+ buf.getBytes(aggr, sz);
+ add(id, aggr);
+ }
+}
+
+void AggregatorList::serialize(document::ByteBuffer & buf) const
+{
+ buf.putIntNetwork(size());
+ for (const_iterator it(begin()), mt(end()); it != mt; it++) {
+ buf.putIntNetwork(it->first);
+ buf.putIntNetwork(it->second.size());
+ buf.putBytes(it->second, it->second.size());
+ }
+}
+
+uint32_t AggregatorList::getSerializedSize() const
+{
+ size_t sz(sizeof(uint32_t) * (1 + 2*size()));
+ for (const_iterator it(begin()), mt(end()); it != mt; it++) {
+ sz += it->second.size();
+ }
+ return sz;
+}
+
+BlobContainer::BlobContainer(size_t reserve) :
+ _blob(reserve),
+ _offsets()
+{
+ _offsets.push_back(0);
+}
+
+size_t BlobContainer::BlobContainer::append(const void * v, size_t sz)
+{
+ const size_t index(getCount());
+ _offsets.push_back(_offsets.back() + sz);
+ if (getSize() > _blob.size()) {
+ _blob.realloc(getSize()*2);
+ }
+ memcpy(_blob.str() + _offsets[index], v, sz);
+ return index;
+}
+
+void BlobContainer::getBlob(size_t index, const void * & blob, size_t & sz) const
+{
+ blob = _blob.c_str() + _offsets[index];
+ sz = getSize(index);
+}
+
+void BlobContainer::deserialize(document::ByteBuffer & buf)
+{
+ int tmp(0);
+ buf.getIntNetwork(tmp);
+ _offsets.resize(tmp + 1);
+ _offsets[0] = 0;
+ for (size_t i(0), m(getCount()); i < m; i++) {
+ buf.getIntNetwork(tmp);
+ _offsets[i+1] = _offsets[i] + tmp;
+ }
+ _blob.realloc(getSize());
+ buf.getBytes(_blob, getSize());
+}
+
+void BlobContainer::serialize(document::ByteBuffer & buf) const
+{
+ buf.putIntNetwork(getCount());
+ for(size_t i(0), m(getCount()); i < m; i++) {
+ buf.putIntNetwork(getSize(i));
+ }
+ buf.putBytes(_blob, getSize());
+}
+
+SearchResult::SearchResult() :
+ _totalHits(0),
+ _wantedHits(10),
+ _hits(),
+ _docIdBuffer(),
+ _numDocIdBytes(0)
+{
+ _docIdBuffer.reset(new vespalib::MallocPtr(4096));
+}
+
+SearchResult::SearchResult(document::ByteBuffer & buf) :
+ _totalHits(0),
+ _wantedHits(10),
+ _hits(),
+ _docIdBuffer(),
+ _numDocIdBytes(0),
+ _aggregatorList(),
+ _groupingList(),
+ _sortBlob()
+{
+ deserialize(buf);
+}
+
+void SearchResult::deserialize(document::ByteBuffer & buf)
+{
+ int32_t tmp;
+ buf.getIntNetwork(tmp); _totalHits = tmp;
+ uint32_t numResults(0), bufSize(0);
+ buf.getIntNetwork(tmp); numResults = tmp;
+ if (numResults > 0) {
+ buf.getIntNetwork(tmp); bufSize = tmp;
+ _docIdBuffer.reset(new vespalib::MallocPtr(bufSize));
+ buf.getBytes(_docIdBuffer->str(), _docIdBuffer->size());
+ _hits.resize(numResults);
+ _numDocIdBytes = _docIdBuffer->size();
+ double rank(0);
+ const char * docIdbp(_docIdBuffer->c_str());
+ for (size_t n(0), m(_hits.size()), p(0); n < m; n++) {
+ buf.getDoubleNetwork(rank);
+ _hits[n] = Hit(0, rank, p, n);
+ while(docIdbp[p++]) { }
+ }
+ }
+ _sortBlob.deserialize(buf);
+ _aggregatorList.deserialize(buf);
+ _groupingList.deserialize(buf);
+}
+
+void SearchResult::serialize(document::ByteBuffer & buf) const
+{
+ buf.putIntNetwork(_totalHits);
+ uint32_t hitCount = std::min(_hits.size(), _wantedHits);
+ buf.putIntNetwork(hitCount);
+ if (hitCount > 0) {
+ uint32_t sz = getBufCount();
+ buf.putIntNetwork(sz);
+ for (size_t i(0), m(hitCount); i < m; i++) {
+ const char * s(_hits[i].getDocId(_docIdBuffer->c_str()));
+ buf.putBytes(s, strlen(s)+1);
+ }
+ for (size_t i(0), m(hitCount); i < m; i++) {
+ buf.putDoubleNetwork(_hits[i].getRank());
+ }
+ }
+ uint32_t sortCount = std::min(_sortBlob.getCount(), _wantedHits);
+ buf.putIntNetwork(sortCount);
+ for (size_t i(0); i < sortCount; i++) {
+ buf.putIntNetwork(_sortBlob.getSize(_hits[i].getIndex()));
+ }
+ for (size_t i(0); i < sortCount; i++) {
+ size_t sz;
+ const void * b;
+ _sortBlob.getBlob(_hits[i].getIndex(), b, sz);
+ buf.putBytes(b, sz);
+ }
+ _aggregatorList.serialize(buf);
+ _groupingList.serialize(buf);
+}
+
+uint32_t SearchResult::getSerializedSize() const
+{
+ uint32_t hitCount = std::min(_hits.size(), _wantedHits);
+ return _aggregatorList.getSerializedSize() +
+ _groupingList.getSerializedSize() +
+ _sortBlob.getSerializedSize() +
+ ((hitCount > 0) ? ((4 * 3) + getBufCount() + sizeof(RankType)*hitCount) : 8);
+}
+
+void SearchResult::addHit(uint32_t lid, const char * docId, RankType rank, const void * sortData, size_t sz)
+{
+ addHit(lid, docId, rank, _sortBlob.getCount());
+ _sortBlob.append(sortData, sz);
+}
+
+void SearchResult::addHit(uint32_t lid, const char * docId, RankType rank, size_t index)
+{
+ const size_t sz(strlen(docId));
+ size_t start = 0;
+ if ( ! _hits.empty() ) {
+ start = getBufCount();
+ }
+ Hit h(lid, rank, start, index);
+ _hits.push_back(h);
+ _totalHits++;
+ _numDocIdBytes += sz + 1;
+ if (_numDocIdBytes > _docIdBuffer->size()) {
+ _docIdBuffer->realloc((_numDocIdBytes)*2);
+ }
+ memcpy(_docIdBuffer->str() + start, docId, sz+1);
+}
+
+void SearchResult::sort()
+{
+ if (_sortBlob.getCount() == 0) {
+ std::sort(_hits.begin(), _hits.end(), std::greater<Hit>());
+ } else {
+ std::sort(_hits.begin(), _hits.end(), SortDataCompare(_sortBlob));
+ }
+}
+
+}
diff --git a/vdslib/src/vespa/vdslib/container/searchresult.h b/vdslib/src/vespa/vdslib/container/searchresult.h
new file mode 100644
index 00000000000..7d19c97122a
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/container/searchresult.h
@@ -0,0 +1,133 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#pragma once
+
+#include <vespa/vespalib/util/memory.h>
+#include <vespa/document/util/bytebuffer.h>
+#include <vector>
+#include <map>
+
+namespace vdslib {
+
+typedef std::map<size_t, vespalib::MallocPtr> IntBlobMapT;
+
+class AggregatorList : public IntBlobMapT
+{
+public:
+ void add(size_t id, const vespalib::MallocPtr & aggrBlob);
+ void deserialize(document::ByteBuffer & buf);
+ void serialize(document::ByteBuffer & buf) const;
+ uint32_t getSerializedSize() const;
+};
+
+class BlobContainer
+{
+public:
+ BlobContainer(size_t reserve=4096);
+ size_t append(const void * v, size_t sz);
+ void getBlob(size_t index, const void * & blob, size_t & sz) const;
+ size_t getCount() const { return _offsets.size() - 1; }
+ size_t getSize() const { return _offsets.back(); }
+ size_t getSize(size_t index) const { return _offsets[index+1] - _offsets[index]; }
+ const void * getBuf(size_t index) const { return _blob.c_str() + _offsets[index]; }
+ void deserialize(document::ByteBuffer & buf);
+ void serialize(document::ByteBuffer & buf) const;
+ uint32_t getSerializedSize() const { return (1 + getCount()) * sizeof(uint32_t) + getSize(); }
+private:
+ typedef vespalib::MallocPtr Blob;
+ Blob _blob;
+ std::vector<size_t> _offsets;
+};
+
+class SearchResult {
+public:
+ typedef double RankType;
+public:
+ SearchResult();
+
+ /**
+ * Constructs a new message from a byte buffer.
+ *
+ * @param buf A byte buffer that contains a serialized message.
+ */
+ SearchResult(document::ByteBuffer & buf);
+
+ AggregatorList & getGroupingList() { return _groupingList; }
+ const AggregatorList & getGroupingList() const { return _groupingList; }
+ AggregatorList & getAggregatorList() { return _aggregatorList; }
+ const AggregatorList & getAggregatorList() const { return _aggregatorList; }
+ void getSortBlob(size_t index, const void * & blob, size_t & sz) const { _sortBlob.getBlob(_hits[index].getIndex(), blob, sz); }
+ void setWantedHitCount(size_t s) { _wantedHits = s; }
+ size_t getWantedHitCount() const { return _wantedHits; }
+ void setTotalHitCount(uint64_t s) { _totalHits = s; }
+ uint64_t getTotalHitCount() const { return _totalHits; }
+ size_t getHitCount() const { return _hits.size(); }
+ size_t getHit(size_t hitNo, const char * & docId, RankType & rank) {
+ rank = _hits[hitNo].getRank();
+ docId = _hits[hitNo].getDocId(_docIdBuffer->c_str());
+ return _hits[hitNo].getLid();
+ }
+ void setRank(size_t hitNo, RankType rank) {
+ _hits[hitNo].setRank(rank);
+ }
+ void addHit(uint32_t lid, const char * docId, RankType rank, size_t index=0);
+ void addHit(uint32_t lid, const char * docId, RankType rank, const void * sortData, size_t sz);
+ void sort();
+
+ void deserialize(document::ByteBuffer & buf);
+ void serialize(document::ByteBuffer & buf) const;
+ uint32_t getSerializedSize() const;
+private:
+ class Hit {
+ public:
+ Hit() : _lid(0), _rank(0), _docIdOffset(0), _index(0) { }
+ Hit(uint32_t lid, RankType rank, size_t docIdOffset, size_t index) : _lid(lid), _rank(rank), _docIdOffset(docIdOffset), _index(index) { }
+ const char * getDocId(const char * base) const { return base + getDocIdOffset(); }
+ uint32_t getLid() const { return _lid; }
+ size_t getDocIdOffset() const { return _docIdOffset; }
+ RankType getRank() const { return _rank; }
+ void setRank(RankType rank) { _rank = rank; }
+ size_t getIndex() const { return _index; }
+ bool operator < (const Hit & h) const { return cmp(h) < 0; }
+ bool operator > (const Hit & h) const { return cmp(h) > 0; }
+ int cmp(const Hit & h) const { return (getRank() < h.getRank()) ? -1 : (getRank() > h.getRank()) ? 1 : 0; }
+ private:
+ uint32_t _lid;
+ RankType _rank;
+ uint32_t _docIdOffset;
+ uint32_t _index; // refers to sortBlob
+ };
+ class SortDataCompare : public std::binary_function<Hit, Hit, bool> {
+ private:
+ const BlobContainer & _sortBlob;
+ public:
+ SortDataCompare(const BlobContainer & sortBlob) : _sortBlob(sortBlob) { }
+ bool operator() (const Hit & x, const Hit & y) const {
+ const void * aBuf, * bBuf;
+ size_t aLen, bLen;
+ _sortBlob.getBlob(x.getIndex(), aBuf, aLen);
+ _sortBlob.getBlob(y.getIndex(), bBuf, bLen);
+ const size_t sz=std::min(aLen, bLen);
+ int diff = memcmp(aBuf, bBuf, sz);
+ if (diff == 0) {
+ diff = aLen - bLen;
+ if (diff == 0) {
+ diff = y.cmp(x);
+ }
+ }
+ return diff < 0;
+ }
+ };
+ size_t getBufCount() const { return _numDocIdBytes; }
+ typedef std::shared_ptr<vespalib::MallocPtr> DocIdBuffer;
+ uint32_t _totalHits;
+ size_t _wantedHits;
+ std::vector<Hit> _hits; // Corresponding rank.
+ DocIdBuffer _docIdBuffer; // Raw zero-terminated documentids in rank order.
+ mutable size_t _numDocIdBytes; // Number of bytes in docId buffer.
+ AggregatorList _aggregatorList;
+ AggregatorList _groupingList;
+ BlobContainer _sortBlob;
+};
+
+}
+
diff --git a/vdslib/src/vespa/vdslib/container/smallvector.h b/vdslib/src/vespa/vdslib/container/smallvector.h
new file mode 100644
index 00000000000..cd6636536c7
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/container/smallvector.h
@@ -0,0 +1,294 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+/**
+ * A vector type implementation that is optimized for keeping a small amount of
+ * elements. If a small amount is kept, no malloc will be done within the
+ * vector implementation.
+ */
+
+#pragma once
+
+#include <boost/array.hpp>
+#include <vespa/fastos/fastos.h>
+#include <iterator>
+#include <memory>
+#include <vector>
+#include <vespa/vespalib/util/printable.h>
+
+namespace storage {
+namespace lib {
+
+/**
+ * A generic iterator implementation using size() and operator[] to access
+ * elements.
+ */
+template<typename Container, typename T>
+class IndexedContainerIterator
+ : public std::iterator<std::random_access_iterator_tag, T>,
+ public vespalib::AsciiPrintable
+{
+ Container* _container;
+ uint64_t _index;
+
+public:
+ typedef IndexedContainerIterator<Container, T> Iterator;
+ typedef typename std::iterator<std::random_access_iterator_tag, T>::difference_type difference_type;
+ // Required to be possible to default construct iterators
+ IndexedContainerIterator() : _container(0), _index(-1) {}
+ IndexedContainerIterator(Container& c, uint64_t index)
+ : _container(&c), _index(index) {}
+
+ T& operator*() { return (*_container)[_index]; }
+ T* operator->() { return &(*_container)[_index]; }
+ bool operator==(const Iterator& o) const {
+ return (_index == o._index);
+ }
+ bool operator!=(const Iterator& o) const {
+ return (_index != o._index);
+ }
+ bool operator<(const Iterator& o) const {
+ return (_index < o._index);
+ }
+
+ Iterator& operator++() {
+ ++_index;
+ return *this;
+ }
+ Iterator operator++(int) {
+ return Iterator(*_container, _index++);
+ }
+ Iterator& operator--() {
+ --_index;
+ return *this;
+ }
+ Iterator operator--(int) {
+ return Iterator(*_container, _index--);
+ }
+
+ Iterator operator+(const difference_type& v) {
+ return Iterator(*_container, _index + v);
+ }
+ difference_type operator+(const Iterator& o) {
+ return _index + o._index;
+ }
+ Iterator operator-(const difference_type& v) {
+ return Iterator(*_container, _index - v);
+ }
+ difference_type operator-(const Iterator& o) {
+ return _index - o._index;
+ }
+
+ void print(vespalib::asciistream& out, const PrintProperties& p) const
+ {
+ out << "Iterator.";
+ if (_index >= _container->size()) {
+ out << "end";
+ } else {
+ out << _index;
+ if (p.verbose()) {
+ out << "(" << (*_container)[_index] << ")";
+ }
+ }
+ }
+};
+
+template <typename T, size_t S = 8>
+class SmallVector : public vespalib::AsciiPrintable {
+ size_t _size;
+ boost::array<T, S> _smallVector;
+ mutable std::unique_ptr< std::vector<T> > _bigVector;
+
+public:
+ typedef IndexedContainerIterator<SmallVector<T, S>, T> iterator;
+ typedef IndexedContainerIterator<const SmallVector<T, S>, const T>
+ const_iterator;
+ typedef T value_type;
+ typedef T& reference;
+ typedef const T& const_reference;
+ typedef size_t difference_type;
+ typedef size_t size_type;
+
+ iterator begin() { return iterator(*this, 0); }
+ iterator end() { return iterator(*this, _size); }
+ const_iterator begin() const { return const_iterator(*this, 0); }
+ const_iterator end() const { return const_iterator(*this, _size); }
+
+ SmallVector() : _size(0) {}
+
+ SmallVector(std::initializer_list<T> elems)
+ : _size(0)
+ {
+ for (auto it=elems.begin(); it != elems.end(); ++it) {
+ push_back(*it);
+ }
+ }
+
+ /** Copy needs to be efficient. That's the whole basis for this class. */
+ SmallVector(const SmallVector<T, S>& other) {
+ operator=(other);
+ }
+ SmallVector<T, S>& operator=(const SmallVector<T, S>& other) {
+ _size = other.size();
+ _smallVector = other._smallVector;
+ if (other._bigVector.get() != 0) {
+ _bigVector.reset(new std::vector<T>());
+ *_bigVector = *other._bigVector;
+ } else {
+ _bigVector.reset();
+ }
+ return *this;
+ }
+
+ template<size_t S2>
+ SmallVector(const SmallVector<T, S2>& other) {
+ operator=(other);
+ }
+ template<size_t S2>
+ SmallVector<T, S>& operator=(const SmallVector<T, S2>& other) {
+ clear();
+ for (uint32_t i=0, n=other.size(); i<n; ++i) {
+ push_back(other[i]);
+ }
+ return *this;
+ }
+
+ size_t getEfficientSizeLimit() const { return S; }
+
+ void push_back(const T& t) {
+ if (_size < S) {
+ _smallVector[_size] = t;
+ ++_size;
+ } else {
+ if (_size == S && _bigVector.get() == 0) {
+ populateVector();
+ }
+ _bigVector->push_back(t);
+ ++_size;
+ }
+ }
+ void pop_back() {
+ if (_size <= S) {
+ --_size;
+ } else {
+ if (--_size == S) {
+ _bigVector.reset();
+ } else {
+ _bigVector->pop_back();
+ }
+ }
+ }
+ const T& back() const { return operator[](_size - 1); }
+ T& back() { return operator[](_size - 1); }
+ const T& front() const { return operator[](0); }
+ T& front() { return operator[](0); }
+ void clear() {
+ _size = 0;
+ _bigVector.reset(0);
+ }
+ const T& operator[](size_t i) const {
+ if (i < S) {
+ return _smallVector[i];
+ } else {
+ return (*_bigVector)[i];
+ }
+ }
+ T& operator[](size_t i) {
+ if (i < S) {
+ return _smallVector[i];
+ } else {
+ return (*_bigVector)[i];
+ }
+ }
+ bool empty() const { return (_size == 0); }
+ size_t size() const { return _size; }
+
+ std::vector<T> getVector() const {
+ std::vector<T> result;
+ if (_bigVector.get() == 0) {
+ for (size_t i=0; i<_size; ++i) {
+ result.push_back(_smallVector[i]);
+ }
+ } else {
+ result = *_bigVector;
+ }
+ return *_bigVector;
+ }
+
+ template<typename O>
+ bool operator==(const O& o) const {
+ if (size() != o.size()) return false;
+ for (size_t i=0; i<_size; ++i) {
+ if ((*this)[i] != o[i]) return false;
+ }
+ return true;
+ }
+ template<typename O>
+ bool operator!=(const O& o) const {
+ return !(operator==(o));
+ }
+
+ void swap(SmallVector<T, S>& other) {
+ // Move current into temporaries
+ size_t copySize(_size);
+ boost::array<T, S> copySmall(_smallVector);
+ std::unique_ptr< std::vector<T> > copyBig(std::move(_bigVector));
+ // Overwrite current with other
+ _size = other._size;
+ _smallVector = other._smallVector;
+ _bigVector = std::move(other._bigVector);
+ // Overwrite other with temporaries
+ other._size = copySize;
+ other._smallVector = copySmall;
+ other._bigVector = std::move(copyBig);
+ }
+
+ void print(vespalib::asciistream& out, const PrintProperties& p) const {
+ if (_size == 0) {
+ out << "[]";
+ return;
+ }
+ vespalib::asciistream ost;
+ ost << operator[](0);
+ bool newLineBetweenEntries = (ost.str().size() > 15);
+ out << "[";
+ for (size_t i=0; i<_size; ++i) {
+ if (i != 0) out << ",";
+ if (newLineBetweenEntries) {
+ out << "\n" << p.indent(1);
+ } else {
+ if (i != 0) { out << " "; }
+ }
+ out << operator[](i);
+ }
+ if (newLineBetweenEntries) {
+ out << "\n" << p.indent();
+ }
+ out << "]";
+ }
+ void erase(iterator eraseIt) {
+ SmallVector<T, S> copy;
+ for (auto it = begin(); it != end(); ++it) {
+ if (it != eraseIt) {
+ copy.push_back(*it);
+ }
+ }
+ copy.swap(*this);
+ }
+
+private:
+ void populateVector() const {
+ assert(_bigVector.get() == 0 && _size == S);
+ _bigVector.reset(new std::vector<T>());
+ for (size_t i=0; i<S; ++i) {
+ _bigVector->push_back(_smallVector[i]);
+ }
+ }
+};
+
+template <typename T, size_t S>
+void
+swap(SmallVector<T, S>& v1, SmallVector<T, S>& v2) {
+ v1.swap(v2);
+}
+
+} // lib
+} // storage
diff --git a/vdslib/src/vespa/vdslib/container/visitorordering.cpp b/vdslib/src/vespa/vdslib/container/visitorordering.cpp
new file mode 100644
index 00000000000..27a4b038959
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/container/visitorordering.cpp
@@ -0,0 +1,15 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#include <vespa/fastos/fastos.h>
+#include "visitorordering.h"
+#include <sstream>
+
+namespace vdslib {
+
+std::string
+VisitorOrdering::toString() const {
+ std::ostringstream ost;
+ ost << (_order == ASCENDING ? "+" : "-") << "," << _widthBits << "," << _divisionBits << "," << _orderingStart;
+ return ost.str();
+}
+
+}
diff --git a/vdslib/src/vespa/vdslib/container/visitorordering.h b/vdslib/src/vespa/vdslib/container/visitorordering.h
new file mode 100644
index 00000000000..3d31a6ac078
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/container/visitorordering.h
@@ -0,0 +1,37 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#pragma once
+
+#include <vespa/fastos/types.h>
+#include <string>
+
+namespace vdslib {
+
+class VisitorOrdering {
+public:
+ enum Order { ASCENDING = 0, DESCENDING };
+
+ VisitorOrdering()
+ : _order(ASCENDING), _orderingStart(0), _widthBits(0), _divisionBits(0) {};
+
+ VisitorOrdering(Order order)
+ : _order(order), _orderingStart(0), _widthBits(0), _divisionBits(0) {};
+
+ VisitorOrdering(Order order, uint64_t orderingStart, uint16_t widthBits, uint16_t divisionBits)
+ : _order(order), _orderingStart(orderingStart), _widthBits(widthBits), _divisionBits(divisionBits) {}
+
+ Order getOrder() const { return _order; }
+ uint64_t getOrderingStart() const { return _orderingStart; }
+ uint16_t getWidthBits() const { return _widthBits; }
+ uint16_t getDivisionBits() const { return _divisionBits; }
+
+ std::string toString() const;
+
+private:
+ Order _order;
+ uint64_t _orderingStart;
+ uint16_t _widthBits;
+ uint16_t _divisionBits;
+};
+
+}
+
diff --git a/vdslib/src/vespa/vdslib/container/visitorstatistics.cpp b/vdslib/src/vespa/vdslib/container/visitorstatistics.cpp
new file mode 100644
index 00000000000..31862e532a9
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/container/visitorstatistics.cpp
@@ -0,0 +1,43 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#include <vespa/fastos/fastos.h>
+#include <vespa/vdslib/container/visitorstatistics.h>
+
+namespace vdslib {
+
+VisitorStatistics::VisitorStatistics()
+ : _bucketsVisited(0),
+ _documentsVisited(0),
+ _bytesVisited(0),
+ _documentsReturned(0),
+ _bytesReturned(0),
+ _secondPassDocumentsReturned(0),
+ _secondPassBytesReturned(0)
+{
+}
+
+VisitorStatistics
+VisitorStatistics::operator+(const VisitorStatistics& other) {
+ VisitorStatistics vs;
+ vs.setBucketsVisited(_bucketsVisited + other._bucketsVisited);
+ vs.setDocumentsVisited(_documentsVisited + other._documentsVisited);
+ vs.setBytesVisited(_bytesVisited + other._bytesVisited);
+ vs.setDocumentsReturned(_documentsReturned + other._documentsReturned);
+ vs.setBytesReturned(_bytesReturned + other._bytesReturned);
+ vs.setSecondPassDocumentsReturned(_secondPassDocumentsReturned + other._secondPassDocumentsReturned);
+ vs.setSecondPassBytesReturned(_secondPassBytesReturned + other._secondPassBytesReturned);
+ return vs;
+}
+
+void
+VisitorStatistics::print(std::ostream& out, bool, const std::string& indent) const
+{
+ out << indent << "Buckets visited: " << _bucketsVisited << "\n";
+ out << indent << "Documents visited: " << _documentsVisited << "\n";
+ out << indent << "Bytes visited: " << _bytesVisited << "\n";
+ out << indent << "Documents returned: " << _documentsReturned << "\n";
+ out << indent << "Bytes returned: " << _bytesReturned << "\n";
+ out << indent << "Documents returned (2nd pass): " << _secondPassDocumentsReturned << "\n";
+ out << indent << "Bytes returned (2nd pass): " << _secondPassBytesReturned << "\n";
+}
+
+}
diff --git a/vdslib/src/vespa/vdslib/container/visitorstatistics.h b/vdslib/src/vespa/vdslib/container/visitorstatistics.h
new file mode 100644
index 00000000000..5812ea25fde
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/container/visitorstatistics.h
@@ -0,0 +1,50 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#pragma once
+
+#include <string>
+#include <stdint.h>
+#include <vespa/document/util/printable.h>
+
+namespace vdslib {
+
+class VisitorStatistics : public document::Printable
+{
+public:
+ VisitorStatistics();
+
+ VisitorStatistics operator+(const VisitorStatistics& other);
+
+ uint32_t getBucketsVisited() const { return _bucketsVisited; }
+ void setBucketsVisited(uint32_t bucketsVisited) { _bucketsVisited = bucketsVisited; }
+
+ uint64_t getDocumentsVisited() const { return _documentsVisited; }
+ void setDocumentsVisited(uint32_t documentsVisited) { _documentsVisited = documentsVisited; }
+
+ uint64_t getBytesVisited() const { return _bytesVisited; }
+ void setBytesVisited(uint32_t bytesVisited) { _bytesVisited = bytesVisited; }
+
+ uint64_t getDocumentsReturned() const { return _documentsReturned; }
+ void setDocumentsReturned(uint32_t documentsReturned) { _documentsReturned = documentsReturned; }
+
+ uint64_t getBytesReturned() const { return _bytesReturned; }
+ void setBytesReturned(uint32_t bytesReturned) { _bytesReturned = bytesReturned; }
+
+ uint64_t getSecondPassDocumentsReturned() const { return _secondPassDocumentsReturned; }
+ void setSecondPassDocumentsReturned(uint32_t documentsReturned) { _secondPassDocumentsReturned = documentsReturned; }
+
+ uint64_t getSecondPassBytesReturned() const { return _secondPassBytesReturned; }
+ void setSecondPassBytesReturned(uint32_t bytesReturned) { _secondPassBytesReturned = bytesReturned; }
+
+ void print(std::ostream& out, bool verbose, const std::string& indent) const;
+private:
+ uint32_t _bucketsVisited;
+ uint64_t _documentsVisited;
+ uint64_t _bytesVisited;
+ uint64_t _documentsReturned;
+ uint64_t _bytesReturned;
+ uint64_t _secondPassDocumentsReturned;
+ uint64_t _secondPassBytesReturned;
+};
+
+}
+
diff --git a/vdslib/src/vespa/vdslib/container/writabledocumentlist.cpp b/vdslib/src/vespa/vdslib/container/writabledocumentlist.cpp
new file mode 100644
index 00000000000..818c3847a45
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/container/writabledocumentlist.cpp
@@ -0,0 +1,95 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#include <vespa/fastos/fastos.h>
+#include <vespa/vdslib/container/writabledocumentlist.h>
+
+#include <vespa/log/log.h>
+
+LOG_SETUP(".vdslib.container.writabledocumentlist");
+
+namespace vdslib {
+WritableDocumentList::WritableDocumentList(const document::DocumentTypeRepo::SP & repo, char* buffer, uint32_t bufferSize, bool keepexisting)
+ : MutableDocumentList(repo, buffer, bufferSize, keepexisting)
+{
+}
+
+WritableDocumentList::WritableDocumentList(const DocumentList& source,
+ char* buffer,
+ uint32_t bufferSize)
+ : MutableDocumentList(source, buffer, bufferSize)
+{
+}
+
+char*
+WritableDocumentList::prepareMultiput(uint32_t count, uint32_t contentSize)
+{
+ //printState("Prepare multiput");
+ uint32_t freeSpace = countFree();
+ uint32_t metaSpace = count * sizeof(MetaEntry);
+ if (freeSpace < metaSpace || freeSpace - metaSpace < contentSize) {
+ return 0;
+ }
+ return _freePtr - contentSize;
+}
+
+bool
+WritableDocumentList::commitMultiput(const std::vector<MetaEntry>& meta, char* contentPtr)
+{
+ //printState("Pre commit multiput");
+ uint32_t diff = contentPtr - _buffer;
+ uint32_t oldDocCount = docCount();
+ uint32_t highPos = 0;
+ uint32_t nlowPos = (_freePtr - _buffer);
+ for (uint32_t i=0; i<meta.size(); ++i) {
+ MetaEntry& entry(getMeta(oldDocCount + i));
+ entry = meta[i];
+ if (entry.headerLen != 0) {
+ entry.headerPos += diff;
+ nlowPos = std::min(nlowPos, entry.headerPos);
+ highPos = std::max(highPos, entry.headerPos + entry.headerLen);
+ }
+ if (entry.bodyLen != 0) {
+ entry.bodyPos += diff;
+ nlowPos = std::min(nlowPos, entry.bodyPos);
+ highPos = std::max(highPos, entry.bodyPos + entry.bodyLen);
+ }
+ }
+ // check for waste after written blocks
+ uint32_t freePos = _freePtr - _buffer;
+ if (freePos < highPos) {
+ vespalib::string msg = vespalib::make_string(
+ "bad multiput, reserved(%lu) < actual use(%d)",
+ (_freePtr - contentPtr), (highPos - diff));
+ throw vespalib::IllegalArgumentException(msg, VESPA_STRLOC);
+ }
+ if (freePos > highPos) {
+ LOG(debug, "filling %u bytes with 0xFF", (freePos - highPos));
+ memset(_buffer + highPos, 0xff, (freePos - highPos));
+ _wasted += (freePos - highPos);
+ }
+
+ // Here we should have written all. Commit alterations.
+ _freePtr = contentPtr;
+
+ // check for waste before written blocks
+ freePos = _freePtr - _buffer;
+ if (freePos < nlowPos) {
+ LOG(debug, "filling %u bytes with 0xFF", (nlowPos - freePos));
+ memset(_buffer + freePos, 0xff, (nlowPos - freePos));
+ _wasted += (nlowPos - freePos);
+ }
+ if (freePos > nlowPos) {
+ vespalib::string msg = vespalib::make_string(
+ "bad multiput, wrote at %p (before allocated %p)",
+ _buffer + nlowPos, contentPtr);
+ throw vespalib::IllegalArgumentException(msg, VESPA_STRLOC);
+ }
+
+ docCount() += meta.size();
+ //printState("Post commit multiput");
+
+ checkConsistency();
+
+ return true;
+}
+
+} // vdslib
diff --git a/vdslib/src/vespa/vdslib/container/writabledocumentlist.h b/vdslib/src/vespa/vdslib/container/writabledocumentlist.h
new file mode 100644
index 00000000000..53c6e45526d
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/container/writabledocumentlist.h
@@ -0,0 +1,46 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+/**
+ * @class storage::api::WritableDocumentList
+ * @ingroup messageapi
+ *
+ * @brief A utility class for a buffer containing a list of documents.
+ *
+ * When writing to the docblock, it will typically be filled up from the end
+ * and forwards, until the free gap between the meta entry list and the data
+ * it uses, is so small that no more entry fits.
+ *
+ * @version $Id$
+ */
+
+#pragma once
+
+#include <vespa/vdslib/container/mutabledocumentlist.h>
+
+namespace vdslib {
+
+class WritableDocumentList : public MutableDocumentList {
+public:
+ /**
+ * Create a new docblock, using the given buffer.
+ * @param keepexisting If set to true, assume buffer is already filled.
+ */
+ WritableDocumentList(const document::DocumentTypeRepo::SP & repo, char* buffer, uint32_t bufferSize, bool keepexisting = false);
+
+ WritableDocumentList(const DocumentList& source, char* buffer, uint32_t bufferSize);
+ /**
+ * Prepare a multiput/remove.
+ * Returns a char* to the part of the buffer you can write contentSize
+ * data to. (Both header and body data), 0 if not enough space.
+ */
+ char* prepareMultiput(uint32_t docCount, uint32_t contentSize);
+ /**
+ * Commit a multiput/remove. Call this after you've written all content to
+ * contentPos gotten from prepareMultiput(). Give relative positions from
+ * contentPos in meta entries.
+ */
+ bool commitMultiput(const std::vector<MetaEntry>& meta, char* contentPos);
+
+};
+
+} // vdslib
+
diff --git a/vdslib/src/vespa/vdslib/defs.h b/vdslib/src/vespa/vdslib/defs.h
new file mode 100644
index 00000000000..da4a4589715
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/defs.h
@@ -0,0 +1,10 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+namespace vdslib {
+
+typedef uint64_t Timestamp;
+const Timestamp MAX_TIMESTAMP = (Timestamp)-1ll;
+
+}
+
+
diff --git a/vdslib/src/vespa/vdslib/distribution/.gitignore b/vdslib/src/vespa/vdslib/distribution/.gitignore
new file mode 100644
index 00000000000..583460ae288
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/distribution/.gitignore
@@ -0,0 +1,3 @@
+*.So
+.depend
+Makefile
diff --git a/vdslib/src/vespa/vdslib/distribution/CMakeLists.txt b/vdslib/src/vespa/vdslib/distribution/CMakeLists.txt
new file mode 100644
index 00000000000..0f86ffee0b8
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/distribution/CMakeLists.txt
@@ -0,0 +1,8 @@
+# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_library(vdslib_distribution OBJECT
+ SOURCES
+ group.cpp
+ distribution.cpp
+ redundancygroupdistribution.cpp
+ DEPENDS
+)
diff --git a/vdslib/src/vespa/vdslib/distribution/distribution.cpp b/vdslib/src/vespa/vdslib/distribution/distribution.cpp
new file mode 100644
index 00000000000..0ed571b1b35
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/distribution/distribution.cpp
@@ -0,0 +1,675 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/fastos/fastos.h>
+#include <vespa/vdslib/distribution/distribution.h>
+
+#include <cmath>
+#include <vespa/document/bucket/bucketid.h>
+#include <vespa/log/log.h>
+#include <vespa/vespalib/text/stringtokenizer.h>
+#include <vespa/vdslib/state/clusterstate.h>
+#include <vespa/vespalib/util/bobhash.h>
+#include <vespa/vespalib/text/stringtokenizer.h>
+#include <vespa/vespalib/stllike/asciistream.h>
+#include <boost/lexical_cast.hpp>
+#include <vespa/config/config.h>
+#include <vespa/config/common/misc.h>
+#include <vespa/config/print/asciiconfigwriter.h>
+#include <vespa/config/print/asciiconfigreader.h>
+
+LOG_SETUP(".vdslib.distribution");
+
+namespace storage {
+namespace lib {
+
+namespace {
+ std::vector<uint32_t> getDistributionBitMasks() {
+ std::vector<uint32_t> masks;
+ masks.resize(32 + 1);
+ uint32_t mask = 0;
+ for (uint32_t i=0; i<=32; ++i) {
+ masks[i] = mask;
+ mask = (mask << 1) | 1;
+ }
+ return masks;
+ }
+}
+
+VESPA_IMPLEMENT_EXCEPTION(NoDistributorsAvailableException, vespalib::Exception);
+VESPA_IMPLEMENT_EXCEPTION(TooFewBucketBitsInUseException, vespalib::Exception);
+
+Distribution::Distribution()
+ : _distributionBitMasks(getDistributionBitMasks()),
+ _nodeGraph(),
+ _redundancy(),
+ _initialRedundancy(0),
+ _ensurePrimaryPersisted(true),
+ _diskDistribution()
+{
+ vespa::config::content::StorDistributionConfig& config(
+ getDefaultDistributionConfig(0, 0));
+ vespalib::asciistream ost;
+ config::AsciiConfigWriter writer(ost);
+ writer.write(config);
+ _serialized = ost.str();
+ configure(config);
+}
+
+Distribution::Distribution(const Distribution& d)
+ : _distributionBitMasks(getDistributionBitMasks()),
+ _nodeGraph(),
+ _redundancy(),
+ _initialRedundancy(0),
+ _ensurePrimaryPersisted(true),
+ _diskDistribution(),
+ _serialized(d._serialized)
+{
+ vespalib::asciistream ist(_serialized);
+ config::AsciiConfigReader<vespa::config::content::StorDistributionConfig> reader(ist);
+ configure(*reader.read());
+}
+
+Distribution::Distribution(const vespa::config::content::StorDistributionConfig& config)
+ : _distributionBitMasks(getDistributionBitMasks()),
+ _nodeGraph(),
+ _redundancy(),
+ _initialRedundancy(0),
+ _ensurePrimaryPersisted(true),
+ _diskDistribution()
+{
+ vespalib::asciistream ost;
+ config::AsciiConfigWriter writer(ost);
+ writer.write(config);
+ _serialized = ost.str();
+ configure(config);
+}
+
+Distribution::Distribution(const vespalib::string& serialized)
+ : _distributionBitMasks(getDistributionBitMasks()),
+ _nodeGraph(),
+ _redundancy(),
+ _initialRedundancy(0),
+ _ensurePrimaryPersisted(true),
+ _diskDistribution(),
+ _serialized(serialized)
+{
+ vespalib::asciistream ist(_serialized);
+ config::AsciiConfigReader<vespa::config::content::StorDistributionConfig> reader(ist);
+ configure(*reader.read());
+}
+
+Distribution&
+Distribution::operator=(const Distribution& d)
+{
+ vespalib::asciistream ist(d.serialize());
+ config::AsciiConfigReader<vespa::config::content::StorDistributionConfig> reader(ist);
+ configure(*reader.read());
+ return *this;
+}
+
+namespace {
+ std::vector<uint16_t> getGroupPath(const vespalib::stringref & path) {
+ vespalib::StringTokenizer st(path, ".", "");
+ std::vector<uint16_t> result(st.size());
+ for (uint32_t i=0, n=result.size(); i<n; ++i) {
+ result[i] = boost::lexical_cast<uint16_t>(st[i]);
+ }
+ return result;
+ }
+}
+
+void
+Distribution::configure(const vespa::config::content::StorDistributionConfig& config)
+{
+ typedef vespa::config::content::StorDistributionConfig::Group ConfigGroup;
+ std::unique_ptr<Group> nodeGraph;
+ for (uint32_t i=0, n=config.group.size(); i<n; ++i) {
+ const ConfigGroup& cg(config.group[i]);
+ std::vector<uint16_t> path;
+ if (nodeGraph.get() != 0) {
+ path = getGroupPath(cg.index);
+ }
+ bool isLeafGroup = (cg.nodes.size() > 0);
+ std::unique_ptr<Group> group;
+ uint16_t index = (path.empty() ? 0 : path.back());
+ if (isLeafGroup) {
+ group.reset(new Group(index, cg.name));
+ } else {
+ group.reset(new Group(
+ index, cg.name,
+ Group::Distribution(cg.partitions), config.redundancy));
+ }
+ group->setCapacity(cg.capacity);
+ if (isLeafGroup) {
+ std::vector<uint16_t> nodes(cg.nodes.size());
+ for (uint32_t j=0, m=nodes.size(); j<m; ++j) {
+ nodes[j] = cg.nodes[j].index;
+ }
+ group->setNodes(nodes);
+ }
+ if (path.empty()) {
+ nodeGraph = std::move(group);
+ } else {
+ assert(nodeGraph.get() != 0);
+ Group* parent = nodeGraph.get();
+ for (uint32_t j=0; j<path.size() - 1; ++j) {
+ parent = parent->getSubGroups()[path[j]];
+ }
+ parent->addSubGroup(std::move(group));
+ }
+ }
+ if (nodeGraph.get() == 0) {
+ throw vespalib::IllegalStateException(
+ "Got config that didn't seem to specify even a root group. Must "
+ "have a root group at minimum:\n"
+ + _serialized, VESPA_STRLOC);
+ }
+ nodeGraph->calculateDistributionHashValues();
+ _nodeGraph = std::move(nodeGraph);
+ _redundancy = config.redundancy;
+ _initialRedundancy = config.initialRedundancy;
+ _ensurePrimaryPersisted = config.ensurePrimaryPersisted;
+ _diskDistribution = config.diskDistribution;
+ _readyCopies = config.readyCopies;
+ _activePerGroup = config.activePerLeafGroup;
+ _distributorAutoOwnershipTransferOnWholeGroupDown
+ = config.distributorAutoOwnershipTransferOnWholeGroupDown;
+}
+
+uint32_t
+Distribution::getGroupSeed(
+ const document::BucketId& bucket, const ClusterState& clusterState,
+ const Group& group) const
+{
+ uint32_t seed(static_cast<uint32_t>(bucket.getRawId())
+ & _distributionBitMasks[clusterState.getDistributionBitCount()]);
+ seed ^= group.getDistributionHash();
+ return seed;
+}
+
+uint32_t
+Distribution::getDistributorSeed(
+ const document::BucketId& bucket, const ClusterState& state) const
+{
+ uint32_t seed(static_cast<uint32_t>(bucket.getRawId())
+ & _distributionBitMasks[state.getDistributionBitCount()]);
+ return seed;
+}
+
+uint32_t
+Distribution::getStorageSeed(
+ const document::BucketId& bucket, const ClusterState& state) const
+{
+ uint32_t seed(static_cast<uint32_t>(bucket.getRawId())
+ & _distributionBitMasks[state.getDistributionBitCount()]);
+
+ if (bucket.getUsedBits() > 33) {
+ int usedBits = bucket.getUsedBits() - 1;
+ seed ^= (_distributionBitMasks[usedBits - 32]
+ & (bucket.getRawId() >> 32)) << 6;
+ }
+ return seed;
+}
+
+uint32_t
+Distribution::getDiskSeed(
+ const document::BucketId& bucket, uint16_t nodeIndex) const
+{
+ typedef vespa::config::content::StorDistributionConfig Config;
+ switch (_diskDistribution) {
+ case Config::MODULO:
+ {
+ uint32_t seed(static_cast<uint32_t>(bucket.getRawId())
+ & _distributionBitMasks[16]);
+ return 0xdeadbeef ^ seed;
+ }
+ case Config::MODULO_INDEX:
+ {
+ uint32_t seed(static_cast<uint32_t>(bucket.getRawId())
+ & _distributionBitMasks[16]);
+ return 0xdeadbeef ^ seed ^ nodeIndex;
+ }
+ case Config::MODULO_KNUTH:
+ {
+ uint32_t seed(static_cast<uint32_t>(bucket.getRawId())
+ & _distributionBitMasks[16]);
+ return 0xdeadbeef ^ seed ^ (1664525L * nodeIndex + 1013904223L);
+ }
+ case Config::MODULO_BID:
+ {
+ uint64_t currentid = bucket.withoutCountBits();
+ char ordered[8];
+ ordered[0] = currentid >> (0*8);
+ ordered[1] = currentid >> (1*8);
+ ordered[2] = currentid >> (2*8);
+ ordered[3] = currentid >> (3*8);
+ ordered[4] = currentid >> (4*8);
+ ordered[5] = currentid >> (5*8);
+ ordered[6] = currentid >> (6*8);
+ ordered[7] = currentid >> (7*8);
+ uint32_t initval = (1664525 * nodeIndex + 0xdeadbeef);
+ return vespalib::BobHash::hash(ordered, 8, initval);
+ }
+ }
+ throw vespalib::IllegalStateException("Unknown disk distribution: "
+ + Config::getDiskDistributionName(_diskDistribution), VESPA_STRLOC);
+}
+
+
+// This function should only depend on disk distribution and node index. It is
+// assumed that any other change, for instance in hierarchical grouping, does
+// not change disk index on disk.
+uint16_t
+Distribution::getIdealDisk(const NodeState& nodeState, uint16_t nodeIndex,
+ const document::BucketId& bucket,
+ DISK_MODE flag) const
+{
+ // Catch special cases in a single if statement
+ if (nodeState.getDiskCount() < 2) {
+ if (nodeState.getDiskCount() == 1) return 0;
+ throw vespalib::IllegalArgumentException(
+ "Cannot pick ideal disk without knowing disk count.",
+ VESPA_STRLOC);
+ }
+ RandomGen randomizer(getDiskSeed(bucket, nodeIndex));
+ switch (_diskDistribution) {
+ case vespa::config::content::StorDistributionConfig::MODULO_BID:
+ {
+ double maxScore = 0.0;
+ uint16_t idealDisk = 0xffff;
+ for (uint32_t i=0, n=nodeState.getDiskCount(); i<n; ++i) {
+ double score = randomizer.nextDouble();
+ const DiskState& diskState(nodeState.getDiskState(i));
+ if (flag == BEST_AVAILABLE_DISK
+ && !diskState.getState().oneOf("uis"))
+ {
+ continue;
+ }
+ if (diskState.getCapacity() != 1.0) {
+ score = pow(score,
+ 1.0 / diskState.getCapacity().getValue());
+ }
+ if (score > maxScore) {
+ maxScore = score;
+ idealDisk = i;
+ }
+ }
+ if (idealDisk == 0xffff) {
+ throw vespalib::IllegalStateException(
+ "There are no available disks.", VESPA_STRLOC);
+ }
+ return idealDisk;
+ }
+ default:
+ {
+ return randomizer.nextUint32() % nodeState.getDiskCount();
+ }
+ }
+}
+
+namespace {
+
+ /** Used to record scored groups during ideal groups calculation. */
+ struct ScoredGroup {
+ const Group* _group;
+ double _score;
+
+ ScoredGroup(const Group* group, double score)
+ : _group(group), _score(score) {}
+
+ bool operator<(const ScoredGroup& other) const {
+ return (_score > other._score);
+ }
+ };
+
+ /** Used to record scored nodes during ideal nodes calculation. */
+ struct ScoredNode {
+ uint16_t _index;
+ uint16_t _reliability;
+ double _score;
+
+ ScoredNode(uint16_t index, uint16_t reliability, double score)
+ : _index(index), _reliability(reliability), _score(score) {}
+
+ bool operator<(const ScoredNode& other) const {
+ return (_score < other._score);
+ }
+ };
+
+ struct IndexSorter {
+ const std::vector<ScoredGroup>& _groups;
+
+ IndexSorter(const std::vector<ScoredGroup>& groups) : _groups(groups) {}
+
+ bool operator()(uint16_t a, uint16_t b) {
+ return (_groups[a]._group->getIndex()
+ < _groups[b]._group->getIndex());
+ }
+ };
+
+ /**
+ * Throw away last entries until throwing away another would
+ * decrease redundancy below total reliability. If redundancy !=
+ * total reliability, see if non-last entries can be removed.
+ */
+ void trimResult(std::list<ScoredNode>& nodes, uint16_t redundancy) {
+ // Initially record total reliability and use the first elements
+ // until satisfied.
+ uint32_t totalReliability = 0;
+ for (std::list<ScoredNode>::iterator it = nodes.begin();
+ it != nodes.end(); ++it)
+ {
+ if (totalReliability >= redundancy || it->_reliability == 0) {
+ nodes.erase(it, nodes.end());
+ break;
+ }
+ totalReliability += it->_reliability;
+ }
+ // If we have too high reliability, see if we can remove something
+ // else
+ if (totalReliability > redundancy) {
+ for (std::list<ScoredNode>::reverse_iterator it = nodes.rbegin();
+ it != nodes.rend();)
+ {
+ if (it->_reliability <= (totalReliability - redundancy)) {
+ totalReliability -= it->_reliability;
+ std::list<ScoredNode>::iterator deleteIt(it.base());
+ ++it;
+ nodes.erase(--deleteIt);
+ if (totalReliability == redundancy) break;
+ } else {
+ ++it;
+ }
+ }
+ }
+ }
+}
+
+void
+Distribution::getIdealGroups(const document::BucketId& bucket,
+ const ClusterState& clusterState,
+ const Group& parent,
+ uint16_t redundancy,
+ std::vector<ResultGroup>& results) const
+{
+ if (parent.isLeafGroup()) {
+ results.push_back(ResultGroup(parent, redundancy));
+ return;
+ }
+ const Group::Distribution& redundancyArray(
+ parent.getDistribution(redundancy));
+ std::vector<ScoredGroup> tmpResults(redundancyArray.size(),
+ ScoredGroup(0, 0));
+ uint32_t seed(getGroupSeed(bucket, clusterState, parent));
+ RandomGen random(seed);
+ uint32_t currentIndex = 0;
+ const std::map<uint16_t, Group*>& subGroups(parent.getSubGroups());
+ for (std::map<uint16_t, Group*>::const_iterator it = subGroups.begin();
+ it != subGroups.end(); ++it)
+ {
+ while (it->first < currentIndex++) random.nextDouble();
+ double score = random.nextDouble();
+ if (it->second->getCapacity() != 1) {
+ // Capacity shouldn't possibly be 0.
+ // Verified in Group::setCapacity()
+ score = pow(score, 1.0 / it->second->getCapacity().getValue());
+ }
+ if (score > tmpResults.back()._score) {
+ tmpResults.push_back(ScoredGroup(it->second, score));
+ std::sort(tmpResults.begin(), tmpResults.end());
+ tmpResults.pop_back();
+ }
+ }
+ while (tmpResults.back()._group == 0) {
+ tmpResults.pop_back();
+ }
+ for (uint32_t i=0, n=tmpResults.size(); i<n; ++i) {
+ ScoredGroup& group(tmpResults[i]);
+ // This should never happen. Config should verify that each group
+ // has enough groups beneath them.
+ assert(group._group != 0);
+ getIdealGroups(bucket, clusterState, *group._group,
+ redundancyArray[i], results);
+ }
+}
+
+const Group*
+Distribution::getIdealDistributorGroup(const document::BucketId& bucket,
+ const ClusterState& clusterState,
+ const Group& parent,
+ uint16_t redundancy) const
+{
+ if (parent.isLeafGroup()) {
+ return &parent;
+ }
+ const Group::Distribution& redundancyArray(
+ parent.getDistribution(redundancy));
+ ScoredGroup result(0, 0);
+ uint32_t seed(getGroupSeed(bucket, clusterState, parent));
+ RandomGen random(seed);
+ uint32_t currentIndex = 0;
+ const std::map<uint16_t, Group*>& subGroups(parent.getSubGroups());
+ for (std::map<uint16_t, Group*>::const_iterator it = subGroups.begin();
+ it != subGroups.end(); ++it)
+ {
+ while (it->first < currentIndex++) random.nextDouble();
+ double score = random.nextDouble();
+ if (it->second->getCapacity() != 1) {
+ // Capacity shouldn't possibly be 0.
+ // Verified in Group::setCapacity()
+ score = pow(score, 1.0 / it->second->getCapacity().getValue());
+ }
+ if (score > result._score) {
+ if (!_distributorAutoOwnershipTransferOnWholeGroupDown
+ || !allDistributorsDown(*it->second, clusterState))
+ {
+ result = ScoredGroup(it->second, score);
+ }
+ }
+ }
+ if (result._group == 0) {
+ return 0;
+ }
+ return getIdealDistributorGroup(
+ bucket, clusterState, *result._group, redundancyArray[0]);
+}
+
+bool
+Distribution::allDistributorsDown(const Group& g, const ClusterState& cs)
+{
+ if (g.isLeafGroup()) {
+ for (uint32_t i=0, n=g.getNodes().size(); i<n; ++i) {
+ const NodeState& ns(cs.getNodeState(
+ Node(NodeType::DISTRIBUTOR, g.getNodes()[i])));
+ if (ns.getState().oneOf("ui")) return false;
+ }
+ } else {
+ typedef std::map<uint16_t, Group*> GroupMap;
+ const GroupMap& subGroups(g.getSubGroups());
+ for (GroupMap::const_iterator it = subGroups.begin();
+ it != subGroups.end(); ++it)
+ {
+ if (!allDistributorsDown(*it->second, cs)) return false;
+ }
+ }
+ return true;
+}
+
+void
+Distribution::getIdealNodes(const NodeType& nodeType,
+ const ClusterState& clusterState,
+ const document::BucketId& bucket,
+ std::vector<uint16_t>& resultNodes,
+ const char* upStates,
+ uint16_t redundancy) const
+{
+ if (redundancy == DEFAULT_REDUNDANCY) redundancy = _redundancy;
+ resultNodes.clear();
+ if (redundancy == 0) return;
+
+ // If bucket is split less than distribution bit, we cannot distribute
+ // it. Different nodes own various parts of the bucket.
+ if (bucket.getUsedBits() < clusterState.getDistributionBitCount()) {
+ std::ostringstream ost;
+ ost << "Cannot get ideal state for bucket " << bucket << " using "
+ << bucket.getUsedBits() << " bits when cluster uses "
+ << clusterState.getDistributionBitCount() << " distribution bits.";
+ throw TooFewBucketBitsInUseException(ost.str(), VESPA_STRLOC);
+ }
+ // Find what hierarchical groups we should have copies in
+ std::vector<ResultGroup> _groupDistribution;
+ uint32_t seed;
+ if (nodeType == NodeType::STORAGE) {
+ seed = getStorageSeed(bucket, clusterState);
+ getIdealGroups(bucket, clusterState, *_nodeGraph, redundancy,
+ _groupDistribution);
+ } else {
+ seed = getDistributorSeed(bucket, clusterState);
+ const Group* group(getIdealDistributorGroup(
+ bucket, clusterState, *_nodeGraph, redundancy));
+ if (group == 0) {
+ vespalib::asciistream ss;
+ ss << "There is no legal distributor target in state with version "
+ << clusterState.getVersion();
+ throw NoDistributorsAvailableException(ss.str(), VESPA_STRLOC);
+ }
+ _groupDistribution.push_back(ResultGroup(*group, 1));
+ }
+ RandomGen random(seed);
+ uint32_t randomIndex = 0;
+ for (uint32_t i=0, n=_groupDistribution.size(); i<n; ++i) {
+ uint16_t groupRedundancy(_groupDistribution[i]._redundancy);
+ const std::vector<uint16_t>& nodes(
+ _groupDistribution[i]._group->getNodes());
+ // Create temporary place to hold results. Use double linked list
+ // for cheap access to back(). Stuff in redundancy fake entries to
+ // avoid needing to check size during iteration.
+ std::list<ScoredNode> tmpResults(groupRedundancy, ScoredNode(0, 0, 0));
+ for (uint32_t j=0, m=nodes.size(); j<m; ++j) {
+ // Verify that the node is legal target before starting to grab
+ // random number. Helps worst case of having to start new random
+ // seed if the node that is out of order is illegal anyways.
+ const NodeState& nodeState(
+ clusterState.getNodeState(Node(nodeType, nodes[j])));
+ if (!nodeState.getState().oneOf(upStates)) continue;
+ if (nodeState.isAnyDiskDown()) {
+ uint16_t idealDiskIndex(getIdealDisk(
+ nodeState, nodes[j], bucket, IDEAL_DISK_EVEN_IF_DOWN));
+ if (nodeState.getDiskState(idealDiskIndex).getState()
+ != State::UP)
+ {
+ continue;
+ }
+ }
+ // Get the score from the random number generator. Make sure we
+ // pick correct random number. Optimize for the case where we
+ // pick in rising order.
+ if (nodes[j] != randomIndex) {
+ if (nodes[j] < randomIndex) {
+ random.setSeed(seed);
+ randomIndex = 0;
+ }
+ for (uint32_t k=randomIndex, o=nodes[j]; k<o; ++k) {
+ random.nextDouble();
+ }
+ randomIndex = nodes[j];
+ }
+ double score = random.nextDouble();
+ ++randomIndex;
+ if (nodeState.getCapacity() != vespalib::Double(1.0)) {
+ score = pow(score, 1.0 / nodeState.getCapacity().getValue());
+ }
+ if (score > tmpResults.back()._score) {
+ for (std::list<ScoredNode>::iterator it = tmpResults.begin();
+ it != tmpResults.end(); ++it)
+ {
+ if (score > it->_score) {
+ tmpResults.insert(it, ScoredNode(
+ nodes[j], nodeState.getReliability(), score));
+ break;
+ }
+ }
+ tmpResults.pop_back();
+ }
+ }
+ trimResult(tmpResults, groupRedundancy);
+ for (std::list<ScoredNode>::iterator it = tmpResults.begin();
+ it != tmpResults.end(); ++it)
+ {
+ resultNodes.push_back(it->_index);
+ }
+ }
+}
+
+Distribution::DistributionConfig
+Distribution::getDefaultDistributionConfig(
+ uint16_t redundancy, uint16_t nodeCount,
+ DiskDistribution distr)
+{
+ vespa::config::content::StorDistributionConfigBuilder config;
+ config.redundancy = redundancy;
+ config.group.resize(1);
+ config.group[0].index = "invalid";
+ config.group[0].name = "invalid";
+ config.group[0].partitions = "*";
+ config.group[0].nodes.resize(nodeCount);
+ for (uint16_t i=0; i<nodeCount; ++i) {
+ config.group[0].nodes[i].index = i;
+ }
+ config.diskDistribution = distr;
+ return config;
+}
+
+std::vector<uint16_t>
+Distribution::getIdealStorageNodes(
+ const ClusterState& state, const document::BucketId& bucket,
+ const char* upStates) const
+{
+ std::vector<uint16_t> nodes;
+ getIdealNodes(NodeType::STORAGE, state, bucket, nodes, upStates);
+ return nodes;
+}
+
+uint16_t
+Distribution::getIdealDistributorNode(
+ const ClusterState& state,
+ const document::BucketId& bucket,
+ const char* upStates) const
+{
+ std::vector<uint16_t> nodes;
+ getIdealNodes(NodeType::DISTRIBUTOR, state, bucket, nodes, upStates);
+ assert(nodes.size() <= 1);
+ if (nodes.size() == 0) {
+ vespalib::asciistream ss;
+ ss << "There is no legal distributor target in state with version "
+ << state.getVersion();
+ throw NoDistributorsAvailableException(ss.str(), VESPA_STRLOC);
+ }
+ return nodes[0];
+}
+
+std::vector<Distribution::IndexList>
+Distribution::splitNodesIntoLeafGroups(IndexList nodeList) const
+{
+ std::vector<IndexList> result;
+ std::map<uint16_t, IndexList> nodes;
+ for (uint32_t i=0, n=nodeList.size(); i<n; ++i) {
+ const Group* group(_nodeGraph->getGroupForNode(nodeList[i]));
+ if (group == 0) {
+ LOGBP(warning, "Node %u is not assigned to a group. "
+ "Should not happen?", nodeList[i]);
+ } else {
+ assert(group->isLeafGroup());
+ nodes[group->getIndex()].push_back(nodeList[i]);
+ }
+ }
+ for (std::map<uint16_t, IndexList>::const_iterator it(nodes.begin());
+ it != nodes.end(); ++it)
+ {
+ result.push_back(it->second);
+ }
+ return result;
+}
+
+} // lib
+} // storage
diff --git a/vdslib/src/vespa/vdslib/distribution/distribution.h b/vdslib/src/vespa/vdslib/distribution/distribution.h
new file mode 100644
index 00000000000..263bf403550
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/distribution/distribution.h
@@ -0,0 +1,199 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+/**
+ * \class storage::lib::Distribution
+ * \ingroup distribution
+ *
+ * \brief Class used to distribute load between storage nodes.
+ */
+
+#pragma once
+
+#include <vespa/document/bucket/bucketid.h>
+#include <vespa/vdslib/distribution/group.h>
+#include <vespa/vdslib/state/nodetype.h>
+#include <vespa/config-stor-distribution.h>
+#include <vespa/vespalib/util/exception.h>
+
+namespace storage {
+namespace lib {
+
+VESPA_DEFINE_EXCEPTION(NoDistributorsAvailableException, vespalib::Exception);
+VESPA_DEFINE_EXCEPTION(TooFewBucketBitsInUseException, vespalib::Exception);
+
+class ClusterState;
+class NodeState;
+
+class Distribution : public document::Printable {
+public:
+ typedef std::shared_ptr<Distribution> SP;
+ typedef std::unique_ptr<Distribution> UP;
+ typedef vespa::config::content::StorDistributionConfigBuilder
+ DistributionConfig;
+ typedef DistributionConfig::DiskDistribution DiskDistribution;
+
+private:
+ std::vector<uint32_t> _distributionBitMasks;
+ std::unique_ptr<Group> _nodeGraph;
+ uint16_t _redundancy;
+ uint16_t _initialRedundancy;
+ uint16_t _readyCopies;
+ bool _activePerGroup;
+ bool _ensurePrimaryPersisted;
+ bool _distributorAutoOwnershipTransferOnWholeGroupDown;
+ DiskDistribution _diskDistribution;
+ vespalib::string _serialized;
+
+ struct ResultGroup {
+ const Group* _group;
+ uint16_t _redundancy;
+
+ ResultGroup(const Group& group, uint16_t redundancy)
+ : _group(&group), _redundancy(redundancy) {}
+
+ bool operator<(const ResultGroup& other) const {
+ return _group->getIndex() < other._group->getIndex();
+ }
+ };
+
+ /**
+ * Get seed to use for ideal state algorithm's random number generator
+ * to decide which hierarchical group we should pick.
+ */
+ uint32_t getGroupSeed(
+ const document::BucketId&, const ClusterState&,
+ const Group&) const;
+
+ /**
+ * Get seed to use for ideal state algorithm's random number generator
+ * to decide which distributor node this bucket should be mapped to.
+ */
+ uint32_t getDistributorSeed(
+ const document::BucketId&, const ClusterState&) const;
+ /**
+ * Get seed to use for ideal state algorithm's random number generator
+ * to decide which storage node this bucket should be mapped to.
+ */
+ uint32_t getStorageSeed(
+ const document::BucketId&, const ClusterState&) const;
+ /**
+ * Get seed to use for ideal state algorithm's random number generator
+ * to decide which disk on a storage node this bucket should be mapped to.
+ * Uses node index to ensure that copies of buckets goes to different disks
+ * on different nodes, such that 2 disks missing will have less overlapping
+ * data and all disks will add on some extra load if one disk goes missing.
+ */
+ uint32_t getDiskSeed(
+ const document::BucketId&, uint16_t nodeIndex) const;
+
+ void getIdealGroups(const document::BucketId& bucket,
+ const ClusterState& clusterState,
+ const Group& parent,
+ uint16_t redundancy,
+ std::vector<ResultGroup>& results) const;
+
+ const Group* getIdealDistributorGroup(const document::BucketId& bucket,
+ const ClusterState& clusterState,
+ const Group& parent,
+ uint16_t redundancy) const;
+
+ /**
+ * Since distribution object may be used often in ideal state calculations
+ * we'd like to avoid locking using it. Thus we don't support live config.
+ * You need to create a new distribution object to change it. This function
+ * is thus private so only constructor can call it.
+ */
+ void configure(const vespa::config::content::StorDistributionConfig & config);
+
+public:
+ Distribution();
+ Distribution(const Distribution&);
+ Distribution(const DistributionConfig&);
+ Distribution(const vespalib::string& serialized);
+
+ Distribution& operator=(const Distribution&);
+
+ const vespalib::string& serialize() const { return _serialized; }
+
+ const Group& getNodeGraph() const { return *_nodeGraph; }
+ uint16_t getRedundancy() const { return _redundancy; }
+ uint16_t getInitialRedundancy() const { return _initialRedundancy; }
+ uint16_t getReadyCopies() const { return _readyCopies; }
+ bool ensurePrimaryPersisted() const { return _ensurePrimaryPersisted; }
+ bool distributorAutoOwnershipTransferOnWholeGroupDown() const
+ { return _distributorAutoOwnershipTransferOnWholeGroupDown; }
+ DiskDistribution getDiskDistribution() const { return _diskDistribution; }
+ bool activePerGroup() const { return _activePerGroup; }
+
+ bool operator==(const Distribution& o) const
+ { return (_serialized == o._serialized); }
+ bool operator!=(const Distribution& o) const
+ { return (_serialized != o._serialized); }
+
+ void print(std::ostream& out, bool, const std::string&) const
+ { out << serialize(); }
+
+ /**
+ * Used by bucket position mapper to do a "thread safe" update. Just
+ * changing the primitive _diskDistribution value should be safe as long as
+ * it doesn't matter if it takes some time before the changed value is
+ * seen. (Should remove this once bucket position mapper can be safely
+ * reconfigured while not in use)
+ */
+ void setDiskDistribution(DistributionConfig::DiskDistribution d)
+ { _diskDistribution = d; }
+
+ enum DISK_MODE {
+ IDEAL_DISK_EVEN_IF_DOWN,
+ BEST_AVAILABLE_DISK
+ };
+ uint16_t getIdealDisk(const NodeState&, uint16_t nodeIndex,
+ const document::BucketId&, DISK_MODE flag) const;
+
+ uint16_t getPreferredAvailableDisk(const NodeState& ns, uint16_t nodeIndex,
+ const document::BucketId& bucket) const
+ { return getIdealDisk(ns, nodeIndex, bucket, BEST_AVAILABLE_DISK); }
+
+ /** Simplified wrapper for getIdealNodes() */
+ std::vector<uint16_t> getIdealStorageNodes(
+ const ClusterState&, const document::BucketId&,
+ const char* upStates = "uim") const;
+
+ /** Simplified wrapper for getIdealNodes() */
+ uint16_t getIdealDistributorNode(
+ const ClusterState&, const document::BucketId&,
+ const char* upStates = "uim") const;
+
+ /**
+ * @throws TooFewBucketBitsInUseException If distribution bit count is
+ * larger than the number of bits used in bucket.
+ * @throws NoDistributorsAvailableException If no distributors are available
+ * in any upstate.
+ */
+ enum { DEFAULT_REDUNDANCY = 0xffff };
+ void getIdealNodes(const NodeType&, const ClusterState&,
+ const document::BucketId&, std::vector<uint16_t>& nodes,
+ const char* upStates = "uim",
+ uint16_t redundancy = DEFAULT_REDUNDANCY) const;
+
+ /**
+ * Unit tests can use this function to get raw config for this class to use
+ * with a really simple setup with no hierarchical grouping. This function
+ * should not be used by any production code.
+ */
+ static DistributionConfig getDefaultDistributionConfig(
+ uint16_t redundancy = 2, uint16_t nodeCount = 10,
+ DiskDistribution distr = DistributionConfig::MODULO_BID);
+
+ /**
+ * Utility function used by distributor to split copies into groups to
+ * handle active per group feature.
+ */
+ typedef std::vector<uint16_t> IndexList;
+ std::vector<IndexList> splitNodesIntoLeafGroups(IndexList nodes) const;
+
+ static bool allDistributorsDown(const Group&, const ClusterState&);
+};
+
+} // lib
+} // storage
+
diff --git a/vdslib/src/vespa/vdslib/distribution/group.cpp b/vdslib/src/vespa/vdslib/distribution/group.cpp
new file mode 100644
index 00000000000..f4f94fefe0b
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/distribution/group.cpp
@@ -0,0 +1,200 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/fastos/fastos.h>
+#include <vespa/vdslib/distribution/group.h>
+
+#include <vespa/vdslib/state/random.h>
+#include <vespa/vespalib/util/exceptions.h>
+#include <boost/lexical_cast.hpp>
+#include <algorithm>
+
+namespace storage {
+namespace lib {
+
+Group::Group(uint16_t index, vespalib::stringref name)
+ : _name(name),
+ _index(index),
+ _distributionHash(0),
+ _capacity(1.0),
+ _subGroups(),
+ _nodes()
+{
+}
+
+Group::Group(uint16_t index, vespalib::stringref name,
+ const Distribution& d, uint16_t redundancy)
+ : _name(name),
+ _index(index),
+ _distributionHash(0),
+ _distributionSpec(d),
+ _preCalculated(redundancy + 1),
+ _capacity(1.0),
+ _subGroups(),
+ _nodes()
+{
+ for (uint32_t i=0; i<_preCalculated.size(); ++i) {
+ _preCalculated[i] = Distribution(d, i);
+ }
+}
+
+Group::~Group()
+{
+ for (std::map<uint16_t, Group*>::iterator it = _subGroups.begin();
+ it != _subGroups.end(); ++it)
+ {
+ delete it->second;
+ it->second = 0;
+ }
+}
+
+bool
+Group::operator==(const Group& other) const
+{
+ return (_name == other._name &&
+ _index == other._index &&
+ _distributionSpec == other._distributionSpec &&
+ _preCalculated.size() == other._preCalculated.size() &&
+ _capacity == other._capacity &&
+ _subGroups == other._subGroups &&
+ _nodes == other._nodes);
+}
+
+void
+Group::print(std::ostream& out, bool verbose,
+ const std::string& indent) const {
+ out << "Group(";
+ if (!_name.empty()) {
+ out << "name: " << _name << ", ";
+ }
+ out << "index: " << _index;
+ if (_distributionSpec.size() > 0) {
+ out << ", distribution: " << _distributionSpec;
+ }
+ if (_capacity != 1.0) {
+ out << ", capacity: " << _capacity;
+ }
+ if (_distributionSpec.size() == 0) {
+ out << ", nodes( ";
+ for (uint32_t i = 0; i < _nodes.size(); i++) {
+ out << _nodes[i] << " ";
+ }
+ out << ")";
+ }
+
+ if (_subGroups.size()>0) {
+ out << ", subgroups: " << _subGroups.size();
+ }
+
+ out << ") {";
+
+ if (_subGroups.size()>0) {
+ for (std::map<uint16_t, Group*>::const_iterator it = _subGroups.begin();
+ it != _subGroups.end(); ++it) {
+ out << "\n" << indent << " ";
+ it->second->print(out, verbose, indent + " ");
+ }
+ }
+
+ out << "\n" << indent << "}";
+}
+
+void
+Group::addSubGroup(Group::UP group)
+{
+ if (_distributionSpec.size() == 0) {
+ throw vespalib::IllegalStateException(
+ "Cannot add sub groups to a group without a valid distribution",
+ VESPA_STRLOC);
+ }
+ if (!group.get()) {
+ throw vespalib::IllegalArgumentException(
+ "Cannot add null group.", VESPA_STRLOC);
+ }
+ std::map<uint16_t, Group*>::const_iterator it(
+ _subGroups.find(group->getIndex()));
+ if (it != _subGroups.end()) {
+ throw vespalib::IllegalArgumentException(
+ "Another subgroup with same index is already added.",
+ VESPA_STRLOC);
+ }
+ _subGroups[group->getIndex()] = group.release();
+}
+
+void
+Group::setCapacity(vespalib::Double capacity)
+{
+ if (capacity <= 0) {
+ vespalib::asciistream ost;
+ ost << "Illegal capacity '" << capacity << "'. Capacity "
+ "must be a positive floating point number";
+ throw vespalib::IllegalArgumentException(ost.str(), VESPA_STRLOC);
+ }
+ _capacity = capacity;
+}
+
+void
+Group::setNodes(const std::vector<uint16_t>& nodes)
+{
+ assert(_distributionSpec.size() == 0);
+ _originalNodes = nodes;
+ _nodes = nodes;
+ // Maintain ordering invariant. Required to ensure node score computations
+ // finish in linear time. Failure to maintain invariant may result in
+ // quadratic worst case behavior.
+ std::sort(_nodes.begin(), _nodes.end());
+}
+
+const Group*
+Group::getGroupForNode(uint16_t nodeIdx) const
+{
+ for (uint32_t i = 0; i < _nodes.size(); ++i) {
+ if (_nodes[i] == nodeIdx) {
+ return this;
+ }
+ }
+
+ for (std::map<uint16_t, Group*>::const_iterator iter = _subGroups.begin();
+ iter != _subGroups.end();
+ ++iter) {
+ const Group* g = iter->second->getGroupForNode(nodeIdx);
+ if (g != NULL) {
+ return g;
+ }
+ }
+
+ return NULL;
+}
+
+void
+Group::calculateDistributionHashValues(uint32_t parentHash)
+{
+ _distributionHash = parentHash ^ (1664525L * _index + 1013904223L);
+ for (std::map<uint16_t, Group*>::iterator it = _subGroups.begin();
+ it != _subGroups.end(); ++it)
+ {
+ it->second->calculateDistributionHashValues(_distributionHash);
+ }
+}
+
+void
+Group::getConfigHash(vespalib::asciistream& out) const
+{
+ out << '(' << _index;
+ if (_capacity != 1.0) {
+ out << 'c' << _capacity;
+ }
+ if (isLeafGroup()) {
+ for (uint16_t node : _originalNodes) {
+ out << ';' << node;
+ }
+ } else {
+ out << 'd' << _distributionSpec.toString();
+ for (const auto& subGroup : _subGroups) {
+ subGroup.second->getConfigHash(out);
+ }
+ }
+ out << ')';
+}
+
+} // lib
+} // storage
diff --git a/vdslib/src/vespa/vdslib/distribution/group.h b/vdslib/src/vespa/vdslib/distribution/group.h
new file mode 100644
index 00000000000..138a466a856
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/distribution/group.h
@@ -0,0 +1,113 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+/**
+ * @class vdslib::Group
+ *
+ * Defines a Group object that defines a group of groups/nodes.
+ *
+ * The "1|*" partitions representation is stored as an array of double,
+ * where the star (*) is represented by zero (0).
+ * The subgroups and storagenode/distributor indexes are stored in increasing order.
+ *
+ */
+#pragma once
+
+#include <boost/operators.hpp>
+#include <map>
+#include <vector>
+#include <vespa/vespalib/objects/floatingpointtype.h>
+#include <vespa/config-stor-distribution.h>
+#include <vespa/vdslib/distribution/redundancygroupdistribution.h>
+#include <vespa/vespalib/util/crc.h>
+#include <vespa/vespalib/stllike/asciistream.h>
+
+namespace storage {
+namespace lib {
+
+class IdealGroup;
+class SystemState;
+
+class Group : public document::Printable, public boost::operators<Group>
+{
+public:
+ typedef std::unique_ptr<Group> UP;
+ typedef RedundancyGroupDistribution Distribution;
+
+private:
+ vespalib::string _name;
+ uint16_t _index;
+ uint32_t _distributionHash;
+ Distribution _distributionSpec;
+ std::vector<Distribution> _preCalculated;
+ vespalib::Double _capacity;
+ std::map<uint16_t, Group*> _subGroups; // Set if branch group
+ // Invariant: _nodes is ordered by ascending index value.
+ std::vector<uint16_t> _nodes; // Set if leaf group
+ // Same set of indices as _nodes, but in the order originally given as
+ // part of setNodes(), i.e. may not be ordered.
+ // TODO(vekterli): this can be removed once model code is guaranteed to
+ // output nodes in a well-defined order, i.e. _originalNodes == _nodes.
+ std::vector<uint16_t> _originalNodes;
+
+ void calculateDistributionHashValues(uint32_t parentHash);
+ void getConfigHash(vespalib::asciistream & out) const;
+
+public:
+ // Create leaf node
+ Group(uint16_t index, vespalib::stringref name);
+ // Create branch node
+ Group(uint16_t index, vespalib::stringref name,
+ const Distribution&, uint16_t redundancy);
+ virtual ~Group();
+
+ bool isLeafGroup() const { return _nodes.size() > 0; }
+ bool operator==(const Group& other) const;
+ virtual void print(std::ostream& out, bool verbose,
+ const std::string& indent) const;
+
+ vespalib::Double getCapacity() const { return _capacity; }
+ const vespalib::string & getName() const { return _name; }
+ uint16_t getIndex() const { return _index; }
+ std::map<uint16_t, Group*>& getSubGroups() { return _subGroups; }
+ const std::map<uint16_t, Group*>& getSubGroups() const
+ { return _subGroups; }
+ const std::vector<uint16_t>& getNodes() const { return _nodes; };
+ const Distribution& getDistributionSpec() const
+ { return _distributionSpec; }
+ const Distribution& getDistribution(uint16_t redundancy) const
+ { return _preCalculated[redundancy]; }
+ uint32_t getDistributionHash() const { return _distributionHash; }
+
+ void addSubGroup(Group::UP);
+ void setCapacity(vespalib::Double capacity);
+ void setNodes(const std::vector<uint16_t>& nodes);
+
+ /**
+ * Returns the hierarchical group the given node is in.
+ */
+ const Group* getGroupForNode(uint16_t index) const;
+
+ /**
+ * Calculates distribution hashes, used to create unique values for each
+ * group to XOR their bucket seeds with. Calculated based on index of itself
+ * and parent groups. Call this on the root group to generate all hashes.
+ */
+ void calculateDistributionHashValues() {
+ calculateDistributionHashValues(0x8badf00d);
+ }
+
+ /**
+ * Get a string uniquely describing the parts of the distribution config
+ * that is critical for distribution. Use to match up two different group
+ * instances in order to verify if they would generate the same distribution
+ */
+ vespalib::string getDistributionConfigHash() const {
+ vespalib::asciistream ost;
+ getConfigHash(ost);
+ return ost.str();
+ }
+
+};
+
+} // lib
+} // storage
+
diff --git a/vdslib/src/vespa/vdslib/distribution/idealnodecalculator.h b/vdslib/src/vespa/vdslib/distribution/idealnodecalculator.h
new file mode 100644
index 00000000000..7bab3ff4af4
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/distribution/idealnodecalculator.h
@@ -0,0 +1,101 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+/**
+ * An interface to implement for a calculator calcuting ideal state. It should
+ * be easy to wrap this calculator in a cache. Thus options that seldom change,
+ * are taken in as set parameters, such that existing cache can be invalidated.
+ */
+#pragma once
+
+#include <vespa/document/bucket/bucketid.h>
+#include <vespa/vdslib/container/smallvector.h>
+#include <vespa/vdslib/state/clusterstate.h>
+#include <vespa/vdslib/distribution/distribution.h>
+#include <vespa/vdslib/state/nodetype.h>
+
+namespace storage {
+namespace lib {
+
+/**
+ * A list of ideal nodes, sorted in preferred order. Wraps a vector to hide
+ * unneeded details, and make it easily printable.
+ */
+class IdealNodeList : public document::Printable {
+ SmallVector<Node> _idealNodes;
+
+public:
+ IdealNodeList() : _idealNodes() {}
+
+ void push_back(const Node& node) {
+ _idealNodes.push_back(node);
+ }
+
+ const Node& operator[](uint32_t i) const { return _idealNodes[i]; }
+ uint32_t size() const { return _idealNodes.size(); }
+ bool contains(const Node& n) const {
+ for (uint32_t i=0; i<_idealNodes.size(); ++i) {
+ if (n == _idealNodes[i]) return true;
+ }
+ return false;
+ }
+ uint16_t indexOf(const Node& n) const {
+ for (uint16_t i=0; i<_idealNodes.size(); ++i) {
+ if (n == _idealNodes[i]) return i;
+ }
+ return 0xffff;
+ }
+
+ virtual void print(std::ostream& out, bool /* verbose */,
+ const std::string& /* indent */) const
+ {
+ out << "[";
+ for (uint32_t i=0; i<_idealNodes.size(); ++i) {
+ if (i != 0) out << ", ";
+ out << _idealNodes[i];
+ }
+ out << "]";
+ }
+};
+
+/**
+ * Simple interface to use for those who needs to calculate ideal nodes.
+ */
+class IdealNodeCalculator {
+public:
+ typedef std::shared_ptr<IdealNodeCalculator> SP;
+ enum UpStates {
+ UpInit,
+ UpInitMaintenance,
+ UP_STATE_COUNT
+ };
+
+ virtual ~IdealNodeCalculator() {}
+
+ virtual IdealNodeList getIdealNodes(const NodeType&,
+ const document::BucketId&,
+ UpStates upStates = UpInit) const = 0;
+
+ // Wrapper functions to make prettier call if nodetype is given.
+ IdealNodeList getIdealDistributorNodes(const document::BucketId& bucket,
+ UpStates upStates = UpInit) const
+ { return getIdealNodes(NodeType::DISTRIBUTOR, bucket, upStates); }
+ IdealNodeList getIdealStorageNodes(const document::BucketId& bucket,
+ UpStates upStates = UpInit) const
+ { return getIdealNodes(NodeType::STORAGE, bucket, upStates); }
+};
+
+
+/**
+ * More complex interface that provides a way to alter needed settings not
+ * provided in the function call itself.
+ */
+class IdealNodeCalculatorConfigurable : public IdealNodeCalculator
+{
+public:
+ typedef std::shared_ptr<IdealNodeCalculatorConfigurable> SP;
+
+ virtual void setDistribution(const Distribution&) = 0;
+ virtual void setClusterState(const ClusterState&) = 0;
+};
+
+} // lib
+} // storage
diff --git a/vdslib/src/vespa/vdslib/distribution/idealnodecalculatorcache.h b/vdslib/src/vespa/vdslib/distribution/idealnodecalculatorcache.h
new file mode 100644
index 00000000000..54ffba869bd
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/distribution/idealnodecalculatorcache.h
@@ -0,0 +1,162 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+/**
+ * A cache for an ideal nodes implementation.
+ *
+ * The cache is localized for quick, localized access.
+ * - There is only one spot one request can be cached, so one can quickly
+ * look whether there is a cache entry on that spot.
+ * - Use LSB bits of bucket to lookup entry such that localized entries use
+ * separate cache spots.
+ *
+ *
+ * Making it cheap for localized
+ * access, regardless of real implementation. Basically, uses LSB bits for
+ * buckets, as these are the bits that differ on localized access.
+ */
+#pragma once
+
+#include <vespa/vdslib/container/lruorder.h>
+#include <vespa/vdslib/distribution/idealnodecalculator.h>
+#include <vespa/vespalib/stllike/hash_map.h>
+#include <vespa/vespalib/util/linkedptr.h>
+
+namespace storage {
+namespace lib {
+
+class IdealNodeCalculatorCache : public IdealNodeCalculatorConfigurable {
+ typedef document::BucketId BucketId;
+
+ /** Cache for all buckets for one given type (same upstate and nodetypes) */
+ class TypeCache {
+ struct Entry {
+ IdealNodeList _result;
+ LruOrder<BucketId, TypeCache>::EntryRef _order;
+ };
+ typedef vespalib::hash_map<BucketId, Entry, BucketId::hash> EntryMap;
+
+ const IdealNodeCalculator& _calc;
+ const NodeType& _nodeType;
+ UpStates _upStates;
+ LruOrder<BucketId, TypeCache> _order;
+ EntryMap _entries;
+ uint32_t _hitCount;
+ uint32_t _missCount;
+ public:
+ typedef vespalib::LinkedPtr<TypeCache> LP;
+
+ TypeCache(const IdealNodeCalculator& c, const NodeType& t,
+ UpStates us, uint32_t size)
+ : _calc(c), _nodeType(t), _upStates(us), _order(size, *this),
+ _hitCount(0), _missCount(0) {}
+
+ IdealNodeList get(const document::BucketId& bucket) {
+ EntryMap::const_iterator it(_entries.find(bucket));
+ if (it == _entries.end()) {
+ ++_missCount;
+ Entry& newEntry(_entries[bucket]);
+ newEntry._result = _calc.getIdealNodes(
+ _nodeType, bucket, _upStates);
+ newEntry._order = _order.add(bucket);
+ return newEntry._result;
+ } else {
+ ++_hitCount;
+ _order.moveToStart(it->second._order);
+ return it->second._result;
+ }
+ }
+
+ void removedFromOrder(const BucketId& bucket) {
+ _entries.erase(bucket);
+ }
+
+ void clearCache() {
+ _entries.clear();
+ _order.clear();
+ }
+
+ uint32_t getHitCount() const { return _hitCount; }
+ uint32_t getMissCount() const { return _missCount; }
+ void clearCounts() {
+ _hitCount = 0;
+ _missCount = 0;
+ }
+ };
+ IdealNodeCalculatorConfigurable::SP _calculator;
+ std::vector<TypeCache::LP> _cache;
+
+public:
+ IdealNodeCalculatorCache(IdealNodeCalculatorConfigurable::SP calc,
+ uint32_t cacheSizePerUpTypeCache)
+ : _calculator(calc)
+ {
+ initCache(cacheSizePerUpTypeCache, *calc);
+ }
+
+ virtual void setDistribution(const Distribution& d) {
+ clearCache();
+ _calculator->setDistribution(d);
+ }
+
+ virtual void setClusterState(const ClusterState& cs) {
+ clearCache();
+ _calculator->setClusterState(cs);
+ }
+
+ virtual IdealNodeList getIdealNodes(const NodeType& nodeType,
+ const document::BucketId& bucket,
+ UpStates upStates) const
+ {
+ uint16_t requestType(getCacheType(nodeType, upStates));
+ return _cache[requestType]->get(bucket);
+ }
+
+ uint32_t getHitCount() const {
+ uint32_t count = 0;
+ for (uint32_t i=0; i<_cache.size(); ++i) {
+ count += _cache[i]->getHitCount();
+ }
+ return count;
+ }
+
+ uint32_t getMissCount() const {
+ uint32_t count = 0;
+ for (uint32_t i=0; i<_cache.size(); ++i) {
+ count += _cache[i]->getMissCount();
+ }
+ return count;
+ }
+
+ void clearCounts() {
+ for (uint32_t i=0; i<_cache.size(); ++i) {
+ _cache[i]->clearCounts();
+ }
+ }
+
+private:
+ void clearCache() {
+ for (size_t i=0; i<_cache.size(); ++i) {
+ _cache[i]->clearCache();
+ }
+ }
+
+ void initCache(uint32_t size, IdealNodeCalculator& calc) {
+ _cache.resize(2 * UP_STATE_COUNT);
+ for (uint32_t i=0; i<2; ++i) {
+ const NodeType& nt(i == 0 ? NodeType::DISTRIBUTOR
+ : NodeType::STORAGE);
+ for (uint32_t j=0; j<UP_STATE_COUNT; ++j) {
+ UpStates upStates = (UpStates) j;
+ uint16_t type = getCacheType(nt, upStates);
+ _cache[type].reset(new TypeCache(calc, nt, upStates, size));
+ }
+ }
+ }
+
+ static uint16_t getCacheType(const NodeType& nt, UpStates s) {
+ uint16_t typeEnum = nt;
+ return (s << 1) | typeEnum;
+ }
+};
+
+} // lib
+} // storage
diff --git a/vdslib/src/vespa/vdslib/distribution/idealnodecalculatorimpl.h b/vdslib/src/vespa/vdslib/distribution/idealnodecalculatorimpl.h
new file mode 100644
index 00000000000..43619c4a419
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/distribution/idealnodecalculatorimpl.h
@@ -0,0 +1,64 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+/**
+ * A cache for an ideal nodes implementation. Making it cheap for localized
+ * access, regardless of real implementation.
+ */
+#pragma once
+
+#include <vespa/vdslib/distribution/idealnodecalculator.h>
+
+namespace storage {
+namespace lib {
+
+class IdealNodeCalculatorImpl : public IdealNodeCalculatorConfigurable {
+ std::vector<const char*> _upStates;
+ const Distribution* _distribution;
+ const ClusterState* _clusterState;
+
+public:
+ IdealNodeCalculatorImpl()
+ : _distribution(0),
+ _clusterState(0)
+ {
+ initUpStateMapping();
+ }
+
+ virtual void setDistribution(const Distribution& d) {
+ _distribution = &d;
+ }
+ virtual void setClusterState(const ClusterState& cs) {
+ _clusterState = &cs;
+ }
+
+ virtual IdealNodeList getIdealNodes(const NodeType& nodeType,
+ const document::BucketId& bucket,
+ UpStates upStates) const
+ {
+ assert(_clusterState != 0);
+ assert(_distribution != 0);
+ std::vector<uint16_t> nodes;
+ _distribution->getIdealNodes(nodeType, *_clusterState, bucket, nodes,
+ _upStates[upStates]);
+ IdealNodeList list;
+ for (uint32_t i=0; i<nodes.size(); ++i) {
+ list.push_back(Node(nodeType, nodes[i]));
+ }
+ return list;
+ }
+
+private:
+ void initUpStateMapping() {
+ _upStates.clear();
+ _upStates.resize(UP_STATE_COUNT);
+ _upStates[UpInit] = "ui";
+ _upStates[UpInitMaintenance] = "uim";
+ for (uint32_t i=0; i<_upStates.size(); ++i) {
+ if (_upStates[i] == 0) throw vespalib::IllegalStateException(
+ "Failed to initialize up state. Code likely not updated "
+ "after another upstate was added.", VESPA_STRLOC);
+ }
+ }
+};
+
+} // lib
+} // storage
diff --git a/vdslib/src/vespa/vdslib/distribution/redundancygroupdistribution.cpp b/vdslib/src/vespa/vdslib/distribution/redundancygroupdistribution.cpp
new file mode 100644
index 00000000000..bb621f610e0
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/distribution/redundancygroupdistribution.cpp
@@ -0,0 +1,149 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/vdslib/distribution/redundancygroupdistribution.h>
+
+#include <algorithm>
+#include <boost/lexical_cast.hpp>
+#include <vespa/vespalib/util/exceptions.h>
+#include <vespa/vespalib/text/stringtokenizer.h>
+
+namespace storage {
+namespace lib {
+
+namespace {
+ void verifyLegal(vespalib::StringTokenizer& st,
+ vespalib::stringref serialized)
+ {
+ // First, verify sanity of the serialized string
+ uint32_t firstAsterix = st.size();
+ for (uint32_t i=0; i<st.size(); ++i) {
+ if (i > firstAsterix) {
+ if (st[i] != "*") {
+ throw vespalib::IllegalArgumentException(
+ "Illegal distribution spec \"" + serialized + "\". "
+ "Asterisk specifications must be tailing the "
+ "specification.", VESPA_STRLOC);
+ }
+ continue;
+ }
+ if (i < firstAsterix && st[i] == "*") {
+ firstAsterix = i;
+ continue;
+ }
+ uint32_t number = atoi(st[i].c_str());
+ if (number <= 0 || number >= 256) {
+ throw vespalib::IllegalArgumentException(
+ "Illegal distribution spec \"" + serialized + "\". "
+ "Copy counts must be in the range 1-255.", VESPA_STRLOC);
+ }
+ for (vespalib::StringTokenizer::Token::const_iterator it
+ = st[i].begin(); it != st[i].end(); ++it)
+ {
+ if (*it < '0' || *it > '9') {
+ throw vespalib::IllegalArgumentException(
+ "Illegal distribution spec \"" + serialized + "\". "
+ "Token isn't asterisk or number.", VESPA_STRLOC);
+ }
+ }
+ }
+ }
+
+ std::vector<uint16_t> parse(vespalib::stringref& serialized) {
+ std::vector<uint16_t> result;
+ if (serialized == "") return result;
+ vespalib::StringTokenizer st(serialized, "|");
+ verifyLegal(st, serialized);
+ for (vespalib::StringTokenizer::Iterator it = st.begin();
+ it != st.end(); ++it)
+ {
+ if (*it == "*") {
+ result.push_back(0);
+ } else {
+ result.push_back(boost::lexical_cast<uint16_t>(*it));
+ }
+ }
+ return result;
+ }
+}
+
+RedundancyGroupDistribution::RedundancyGroupDistribution(
+ vespalib::stringref serialized)
+ : _values(parse(serialized))
+{
+}
+
+RedundancyGroupDistribution::RedundancyGroupDistribution(
+ const RedundancyGroupDistribution& spec,
+ uint16_t redundancy)
+{
+ uint16_t firstAsterix = spec.getFirstAsterixIndex();
+ // If redundancy is less than the group size, we only get one copy
+ // in redundancy groups.
+ if (redundancy <= spec.size()) {
+ _values = std::vector<uint16_t>(redundancy, 1);
+ return;
+ }
+ // If not we will have one copy at least for every wanted group.
+ _values = std::vector<uint16_t>(spec.size(), 1);
+ redundancy -= spec.size();
+ // Distribute extra copies to non-asterix entries first
+ redundancy = divideSpecifiedCopies(0, firstAsterix, redundancy, spec._values);
+ // Distribute remaining copies to asterix entries
+ divideSpecifiedCopies(firstAsterix, spec.size(), redundancy, spec._values);
+ // Lastly sort, so the most copies will end up first in ideal state
+ std::sort(_values.begin(), _values.end());
+ std::reverse(_values.begin(), _values.end());
+ assert(_values.front() >= _values.back());
+}
+
+void
+RedundancyGroupDistribution::print(std::ostream& out,
+ bool, const std::string&) const
+{
+ for (uint32_t i=0; i<_values.size(); ++i) {
+ if (i != 0) out << '|';
+ if (_values[i] == 0) {
+ out << '*';
+ } else {
+ out << _values[i];
+ }
+ }
+}
+
+uint16_t
+RedundancyGroupDistribution::getFirstAsterixIndex() const
+{
+ if (_values.empty() || _values.back() != 0) {
+ throw vespalib::IllegalArgumentException(
+ "Invalid spec given. No asterisk entries found.",
+ VESPA_STRLOC);
+ }
+ uint16_t firstAsterix = _values.size() - 1;
+ while (firstAsterix > 0 && _values[firstAsterix - 1] == 0) {
+ --firstAsterix;
+ }
+ return firstAsterix;
+}
+
+uint16_t
+RedundancyGroupDistribution::divideSpecifiedCopies(
+ uint16_t start, uint16_t end,
+ uint16_t redundancy, const std::vector<uint16_t>& maxValues)
+{
+ uint16_t lastRedundancy = redundancy;
+ while (redundancy > 0) {
+ for (uint16_t i=start; i<end && redundancy > 0; ++i) {
+ if (maxValues[i] == 0 || _values[i] < maxValues[i]) {
+ ++_values[i];
+ --redundancy;
+ }
+ }
+ if (redundancy == lastRedundancy) break;
+ lastRedundancy = redundancy;
+ }
+ return redundancy;
+}
+
+} // lib
+} // storage
+
diff --git a/vdslib/src/vespa/vdslib/distribution/redundancygroupdistribution.h b/vdslib/src/vespa/vdslib/distribution/redundancygroupdistribution.h
new file mode 100644
index 00000000000..3b45cc3d612
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/distribution/redundancygroupdistribution.h
@@ -0,0 +1,51 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+/**
+ * Helper class to represent the redundancy arrays from config, dividing
+ * copies between groups, like 2|1|*.
+ *
+ * All asterisk entries must be given last. There must be an asterisk in the end.
+ */
+#pragma once
+
+#include <vespa/document/util/printable.h>
+#include <vector>
+#include <vespa/vespalib/stllike/string.h>
+
+namespace storage {
+namespace lib {
+
+class RedundancyGroupDistribution : public document::Printable {
+ std::vector<uint16_t> _values;
+
+public:
+ RedundancyGroupDistribution() {}
+ /**
+ * Create a group distribution spec from the serialized version.
+ * Asterisk entries are represented as zero.
+ */
+ RedundancyGroupDistribution(vespalib::stringref serialized);
+ /**
+ * Create a group distribution for a given redundancy. Will fail if there
+ * are no asterisk entries in spec. Should prefer to use every copy before
+ * allowing more copies for one group.
+ */
+ RedundancyGroupDistribution(const RedundancyGroupDistribution& spec,
+ uint16_t redundancy);
+
+ uint16_t size() const { return _values.size(); }
+ uint16_t operator[](uint16_t i) const { return _values[i]; }
+
+ bool operator==(const RedundancyGroupDistribution& o) const
+ { return (_values == o._values); }
+
+ void print(std::ostream&, bool verbose, const std::string& indent) const;
+
+private:
+ uint16_t getFirstAsterixIndex() const;
+ uint16_t divideSpecifiedCopies(
+ uint16_t start, uint16_t end,
+ uint16_t redundancy, const std::vector<uint16_t>& maxValues);
+};
+
+} // lib
+} // storage
diff --git a/vdslib/src/vespa/vdslib/state/.gitignore b/vdslib/src/vespa/vdslib/state/.gitignore
new file mode 100644
index 00000000000..ece396fc425
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/state/.gitignore
@@ -0,0 +1,9 @@
+*.lo
+.*.swp
+.depend
+.depend.NEW
+.deps
+.libs
+Makefile
+config-*.cpp
+config-*.h
diff --git a/vdslib/src/vespa/vdslib/state/CMakeLists.txt b/vdslib/src/vespa/vdslib/state/CMakeLists.txt
new file mode 100644
index 00000000000..02df7956ad3
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/state/CMakeLists.txt
@@ -0,0 +1,11 @@
+# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_library(vdslib_state OBJECT
+ SOURCES
+ nodetype.cpp
+ node.cpp
+ state.cpp
+ diskstate.cpp
+ nodestate.cpp
+ clusterstate.cpp
+ DEPENDS
+)
diff --git a/vdslib/src/vespa/vdslib/state/clusterstate.cpp b/vdslib/src/vespa/vdslib/state/clusterstate.cpp
new file mode 100644
index 00000000000..0c65d22cfab
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/state/clusterstate.cpp
@@ -0,0 +1,524 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#include <vespa/fastos/fastos.h>
+#include <vespa/vdslib/state/clusterstate.h>
+
+#include <boost/cast.hpp>
+#include <boost/lexical_cast.hpp>
+#include <vespa/vespalib/text/stringtokenizer.h>
+#include <vespa/document/util/stringutil.h>
+#include <vespa/log/log.h>
+#include <sstream>
+#include <vespa/vdslib/distribution/distribution.h>
+
+LOG_SETUP(".vdslib.state.cluster");
+
+namespace storage {
+namespace lib {
+
+ClusterState::ClusterState()
+ : Printable(),
+ _version(0),
+ _clusterState(&State::DOWN),
+ _nodeStates(),
+ _nodeCount(2),
+ _description(),
+ _distributionBits(16)
+{
+}
+
+ClusterState::ClusterState(const ClusterState& other)
+ : Printable(other),
+ _version(other._version),
+ _clusterState(other._clusterState),
+ _nodeStates(other._nodeStates),
+ _nodeCount(other._nodeCount),
+ _description(other._description),
+ _distributionBits(other._distributionBits)
+{
+}
+
+ClusterState::~ClusterState()
+{
+}
+
+namespace {
+ struct NodeData {
+ bool empty;
+ Node node;
+ vespalib::asciistream ost;
+
+ NodeData() : empty(true), node(NodeType::STORAGE, 0), ost() {}
+
+ void addTo(std::map<Node, NodeState>& nodeStates,
+ std::vector<uint16_t>& nodeCount)
+ {
+ if (!empty) {
+ NodeState state(ost.str(), &node.getType());
+ if (state != NodeState(node.getType(), State::UP)
+ || state.getDescription().size() > 0)
+ {
+ nodeStates.insert(std::make_pair(node, state));
+ }
+ if (nodeCount[node.getType()] <= node.getIndex()) {
+ nodeCount[node.getType()] = node.getIndex() + 1;
+ }
+ empty = true;
+ ost.clear();
+ }
+ }
+ };
+}
+
+ClusterState::ClusterState(const vespalib::stringref & serialized)
+ : Printable(),
+ _version(0),
+ _clusterState(&State::UP),
+ _nodeStates(),
+ _nodeCount(2),
+ _description(),
+ _distributionBits(16)
+{
+ vespalib::StringTokenizer st(serialized, " \t\f\r\n");
+ st.removeEmptyTokens();
+ NodeData nodeData;
+ vespalib::string lastAbsolutePath;
+
+ for (vespalib::StringTokenizer::Iterator it = st.begin();
+ it != st.end(); ++it)
+ {
+ vespalib::string::size_type index = it->find(':');
+ if (index == vespalib::string::npos) {
+ throw vespalib::IllegalArgumentException(
+ "Token " + *it + " does not contain ':': " + serialized,
+ VESPA_STRLOC);
+ }
+ vespalib::stringref key = it->substr(0, index);
+ vespalib::stringref value = it->substr(index + 1);
+ if (key.size() > 0 && key[0] == '.') {
+ if (lastAbsolutePath == "") {
+ throw vespalib::IllegalArgumentException(
+ "The first path in system state string needs to be "
+ "absolute", VESPA_STRLOC);
+ }
+ key = lastAbsolutePath + key;
+ } else {
+ lastAbsolutePath = key;
+ }
+ if (key.size() > 0) switch (key[0]) {
+ case 'c':
+ if (key == "cluster") {
+ setClusterState(State::get(value));
+ continue;
+ }
+ break;
+ case 'b':
+ if (key == "bits") {
+ _distributionBits = atoi(value.c_str());
+ continue;
+ }
+ break;
+ case 'v':
+ if (key == "version") {
+ _version = atoi(value.c_str());
+ continue;
+ }
+ break;
+ case 'm':
+ if (key.size() > 1) break;
+ _description = document::StringUtil::unescape(value);
+ continue;
+ case 'd':
+ case 's':
+ {
+ const NodeType* nodeType(0);
+ vespalib::string::size_type dot = key.find('.');
+ vespalib::stringref type(dot == vespalib::string::npos
+ ? key : key.substr(0, dot));
+ if (type == "storage") {
+ nodeType = &NodeType::STORAGE;
+ } else if (type == "distributor") {
+ nodeType = &NodeType::DISTRIBUTOR;
+ }
+ if (nodeType == 0) break;
+ if (dot == vespalib::string::npos) { // Entry that set node counts
+ uint16_t nodeCount = 0;
+ nodeCount = atoi(value.c_str());
+
+ if (nodeCount > _nodeCount[*nodeType] ) {
+ _nodeCount[*nodeType] = nodeCount;
+ }
+ continue;
+ }
+ vespalib::string::size_type dot2 = key.find('.', dot + 1);
+ Node node;
+ if (dot2 == vespalib::string::npos) {
+ node = Node(*nodeType, atoi(key.substr(dot + 1).c_str()));
+ } else {
+ node = Node(*nodeType, atoi(key.substr(dot + 1, dot2 - dot - 1).c_str()));
+ }
+
+ if (node.getIndex() >= _nodeCount[*nodeType]) {
+ vespalib::asciistream ost;
+ ost << "Cannot index " << *nodeType << " node "
+ << node.getIndex() << " of " << _nodeCount[*nodeType];
+ throw vespalib::IllegalArgumentException(
+ ost.str(), VESPA_STRLOC);
+ }
+ if (nodeData.node != node) {
+ nodeData.addTo(_nodeStates, _nodeCount);
+ }
+ if (dot2 == vespalib::string::npos) {
+ break; // No default key for nodes.
+ } else {
+ nodeData.ost << " " << key.substr(dot2 + 1) << ':' << value;
+ }
+ nodeData.node = node;
+ nodeData.empty = false;
+ continue;
+ }
+ default:
+ break;
+ }
+ LOG(debug, "Unknown key %s in systemstate. Ignoring it, assuming it's "
+ "a new feature from a newer version than ourself: %s",
+ key.c_str(), serialized.c_str());
+ }
+ nodeData.addTo(_nodeStates, _nodeCount);
+ removeExtraElements();
+}
+
+namespace {
+ struct SeparatorPrinter {
+ bool first;
+ SeparatorPrinter() : first(true) {}
+ const char * toString() {
+ if (first) {
+ first = false;
+ return "";
+ }
+ return " ";
+ }
+ };
+}
+
+void
+ClusterState::serialize(vespalib::asciistream & out, bool ignoreNewFeatures) const
+{
+ SeparatorPrinter sep;
+ if (!ignoreNewFeatures && _version != 0) {
+ out << sep.toString() << "version:" << _version;
+ }
+ if (!ignoreNewFeatures && *_clusterState != State::UP) {
+ out << sep.toString() << "cluster:" << _clusterState->serialize();
+ }
+ if (!ignoreNewFeatures && _distributionBits != 16) {
+ out << sep.toString() << "bits:" << _distributionBits;
+ }
+
+ uint16_t distCount = getNodeCount(NodeType::DISTRIBUTOR);
+ if (ignoreNewFeatures || distCount > 0) {
+ out << sep.toString() << "distributor:" << distCount;
+ for (std::map<Node, NodeState>::const_iterator it =
+ _nodeStates.begin();
+ it != _nodeStates.end(); ++it)
+ {
+ if (it->first.getType() != NodeType::DISTRIBUTOR) continue;
+ vespalib::asciistream prefix;
+ prefix << "." << it->first.getIndex() << ".";
+ vespalib::asciistream ost;
+ it->second.serialize(ost, prefix.str(), false, false,
+ ignoreNewFeatures);
+ vespalib::stringref content = ost.str();
+ if (content.size() > 0) {
+ out << " " << content;
+ }
+ }
+ }
+ uint16_t storCount = getNodeCount(NodeType::STORAGE);
+ if (ignoreNewFeatures || storCount > 0) {
+ out << sep.toString() << "storage:" << storCount;
+ for (std::map<Node, NodeState>::const_iterator it =
+ _nodeStates.begin();
+ it != _nodeStates.end(); ++it)
+ {
+ if (it->first.getType() != NodeType::STORAGE) continue;
+ vespalib::asciistream prefix;
+ prefix << "." << it->first.getIndex() << ".";
+ vespalib::asciistream ost;
+ it->second.serialize(ost, prefix.str(), false, false,
+ ignoreNewFeatures);
+ vespalib::stringref content = ost.str();
+ if ( !content.empty()) {
+ out << " " << content;
+ }
+ }
+ }
+}
+
+ClusterState&
+ClusterState::operator=(const ClusterState& other)
+{
+ if (this != &other) {
+ _version = other._version;
+ _clusterState = other._clusterState;
+ _nodeStates = other._nodeStates;
+ _nodeCount = other._nodeCount;
+ _description = other._description;
+ _distributionBits = other._distributionBits;
+ }
+ return *this;
+}
+
+bool
+ClusterState::operator==(const ClusterState& other) const
+{
+ return (_version == other._version &&
+ *_clusterState == *other._clusterState &&
+ _nodeStates == other._nodeStates &&
+ _nodeCount == other._nodeCount &&
+ _distributionBits == other._distributionBits);
+}
+
+bool
+ClusterState::operator!=(const ClusterState& other) const
+{
+ return !(*this == other);
+}
+
+uint16_t
+ClusterState::getNodeCount(const NodeType& type) const
+{
+ return _nodeCount[type];
+}
+
+const NodeState&
+ClusterState::getNodeState(const Node& node) const
+{
+ // If beyond node count, the node is down.
+ if (node.getIndex() >= _nodeCount[node.getType()]) {
+ if (node.getType() == NodeType::STORAGE) {
+ static NodeState defaultSDState(NodeType::STORAGE, State::DOWN);
+ return defaultSDState;
+ } else if (node.getType() == NodeType::DISTRIBUTOR) {
+ static NodeState defaultDDState(NodeType::DISTRIBUTOR, State::DOWN);
+ return defaultDDState;
+ }
+ throw vespalib::IllegalStateException(
+ "Unknown node type " + node.getType().toString(), VESPA_STRLOC);
+ }
+ // If it actually has an entry in map, return that
+ std::map<Node, NodeState>::const_iterator it = _nodeStates.find(node);
+ if (it != _nodeStates.end()) return it->second;
+ // If not mentioned in map but within node count, the node is up
+ if (node.getType() == NodeType::STORAGE) {
+ static NodeState defaultSUState(NodeType::STORAGE, State::UP);
+ return defaultSUState;
+ } else if (node.getType() == NodeType::DISTRIBUTOR) {
+ static NodeState defaultDUState(NodeType::DISTRIBUTOR, State::UP);
+ return defaultDUState;
+ }
+ throw vespalib::IllegalStateException(
+ "Unknown node type " + node.getType().toString(), VESPA_STRLOC);
+}
+
+void
+ClusterState::setClusterState(const State& state)
+{
+ if (!state.validClusterState()) {
+ throw vespalib::IllegalStateException(
+ state.toString(true) + " is not a legal cluster state",
+ VESPA_STRLOC);
+ }
+ _clusterState = &state;
+}
+
+void
+ClusterState::setNodeState(const Node& node, const NodeState& state)
+{
+ state.verifySupportForNodeType(node.getType());
+ if (node.getIndex() >= _nodeCount[node.getType()]) {
+ for (uint32_t i = _nodeCount[node.getType()]; i < node.getIndex(); ++i)
+ {
+ _nodeStates.insert(std::make_pair(
+ Node(node.getType(), i),
+ NodeState(node.getType(), State::DOWN)));
+ }
+ _nodeCount[node.getType()] = node.getIndex() + 1;
+ }
+ if (state == NodeState(node.getType(), State::UP)
+ && state.getDescription().size() == 0)
+ {
+ _nodeStates.erase(node);
+ } else {
+ _nodeStates.insert(std::make_pair(node, state));
+ }
+
+ removeExtraElements();
+}
+
+void
+ClusterState::print(std::ostream& out, bool verbose,
+ const std::string&) const
+{
+ (void) verbose;
+ vespalib::asciistream tmp;
+ serialize(tmp, false);
+ out << tmp.str();
+}
+
+void
+ClusterState::removeExtraElements()
+{
+ // Simplify the system state by removing the last indexes if the nodes
+ // are down.
+ for (uint32_t i=0; i<2; ++i) {
+ const NodeType& type(i == 0 ? NodeType::STORAGE
+ : NodeType::DISTRIBUTOR);
+ for (int32_t index = _nodeCount[type]; index >= 0; --index) {
+ Node node(type, index - 1);
+ std::map<Node, NodeState>::iterator it(_nodeStates.find(node));
+ if (it == _nodeStates.end()) break;
+ if (it->second.getState() != State::DOWN) break;
+ if (it->second.getDescription() != "") break;
+ _nodeStates.erase(it);
+ --_nodeCount[type];
+ }
+ }
+}
+
+void
+ClusterState::getTextualDifference(std::ostringstream& builder, const NodeType& type, const ClusterState& other) const {
+ int maxCount = getNodeCount(type);
+ if (other.getNodeCount(type) > maxCount) {
+ maxCount = other.getNodeCount(type);
+ }
+
+ bool first = true;
+ for (int i = 0; i < maxCount; i++) {
+ Node n(type, i);
+ std::string diff = getNodeState(n).getTextualDifference(other.getNodeState(n));
+ if (diff != "no change") {
+ if (first) {
+ if (builder.str().length() > 0) {
+ builder << " ";
+ }
+ builder << type << " [";
+ first = false;
+ } else {
+ builder << ", ";
+ }
+ builder << i << ": " << diff;
+ }
+ }
+
+ if (!first) {
+ builder << "]";
+ }
+}
+
+std::string
+ClusterState::getTextualDifference(const ClusterState& other) const
+{
+ std::ostringstream builder;
+
+ getTextualDifference(builder, NodeType::STORAGE, other);
+ getTextualDifference(builder, NodeType::DISTRIBUTOR, other);
+
+ return builder.str();
+}
+
+void
+ClusterState::printStateGroupwise(std::ostream& out, const Distribution& dist,
+ bool verbose, const std::string& indent) const
+{
+ out << "ClusterState(Version: " << _version << ", Cluster state: "
+ << _clusterState->toString(true) << ", Distribution bits: "
+ << _distributionBits << ") {";
+ printStateGroupwise(out, dist.getNodeGraph(), verbose, indent + " ", true);
+ out << "\n" << indent << "}";
+}
+
+namespace {
+ template<typename T>
+ std::string getNumberSpec(const std::vector<T>& numbers) {
+ std::ostringstream ost;
+ bool first = true;
+ uint32_t firstInRange = numbers.size() == 0 ? 0 : numbers[0];;
+ uint32_t lastInRange = firstInRange;
+ for (uint32_t i=1; i<=numbers.size(); ++i) {
+ if (i < numbers.size() && numbers[i] == lastInRange + 1) {
+ ++lastInRange;
+ } else {
+ if (first) {
+ first = false;
+ } else {
+ ost << ",";
+ }
+ if (firstInRange == lastInRange) {
+ ost << firstInRange;
+ } else {
+ ost << firstInRange << "-" << lastInRange;
+ }
+ if (i < numbers.size()) {
+ firstInRange = lastInRange = numbers[i];
+ }
+ }
+ }
+ return ost.str();
+ }
+}
+
+void
+ClusterState::printStateGroupwise(std::ostream& out, const Group& group,
+ bool verbose, const std::string& indent,
+ bool rootGroup) const
+{
+ if (rootGroup) {
+ out << "\n" << indent << "Top group";
+ } else {
+ out << "\n" << indent << "Group " << group.getIndex() << ": "
+ << group.getName();
+ if (group.getCapacity() != 1.0) {
+ out << ", capacity " << group.getCapacity();
+ }
+ }
+ out << ".";
+ if (group.isLeafGroup()) {
+ out << " " << group.getNodes().size() << " node"
+ << (group.getNodes().size() != 1 ? "s" : "") << " ["
+ << getNumberSpec(group.getNodes()) << "] {";
+ bool printedAny = false;
+ for (uint32_t j=0; j<2; ++j) {
+ const NodeType& nodeType(
+ j == 0 ? NodeType::DISTRIBUTOR : NodeType::STORAGE);
+ NodeState defState(nodeType, State::UP);
+ for (uint32_t i=0; i<group.getNodes().size(); ++i) {
+ Node node(nodeType, group.getNodes()[i]);
+ const NodeState& state(getNodeState(node));
+ if (state != defState) {
+ out << "\n" << indent << " " << node << ": ";
+ state.print(out, verbose, indent + " ");
+ printedAny = true;
+ }
+ }
+ }
+ if (!printedAny) {
+ out << "\n" << indent << " All nodes in group up and available.";
+ }
+ } else {
+ const std::map<uint16_t, Group*>& children(group.getSubGroups());
+ out << " " << children.size() << " branch"
+ << (children.size() != 1 ? "es" : "") << " with distribution "
+ << group.getDistributionSpec() << " {";
+ for (std::map<uint16_t, Group*>::const_iterator it = children.begin();
+ it != children.end(); ++it)
+ {
+ printStateGroupwise(out, *it->second, verbose,
+ indent + " ", false);
+ }
+ }
+ out << "\n" << indent << "}";
+}
+
+} // lib
+} // storage
diff --git a/vdslib/src/vespa/vdslib/state/clusterstate.h b/vdslib/src/vespa/vdslib/state/clusterstate.h
new file mode 100644
index 00000000000..2d0f73413fd
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/state/clusterstate.h
@@ -0,0 +1,82 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+/**
+ * @class vdslib::ClusterState
+ * @ingroup state
+ *
+ * @brief Object to represent a system state
+ */
+
+#pragma once
+
+#include <map>
+#include <vespa/vdslib/state/node.h>
+#include <vespa/vdslib/state/nodestate.h>
+
+namespace storage {
+namespace lib {
+
+class Distribution;
+class Group;
+
+class ClusterState : public document::Printable {
+ uint32_t _version;
+ const State* _clusterState;
+ std::map<Node, NodeState> _nodeStates;
+ std::vector<uint16_t> _nodeCount;
+ vespalib::string _description;
+ uint16_t _distributionBits;
+
+ void getTextualDifference(std::ostringstream& builder, const NodeType& type,
+ const ClusterState& other) const;
+
+public:
+ typedef std::shared_ptr<const ClusterState> CSP;
+ typedef std::shared_ptr<ClusterState> SP;
+ typedef std::unique_ptr<ClusterState> UP;
+
+ ClusterState();
+ ClusterState(const ClusterState&);
+ explicit ClusterState(const vespalib::stringref & serialized);
+ ~ClusterState();
+
+ std::string getTextualDifference(const ClusterState& other) const;
+ void serialize(vespalib::asciistream & out, bool ignoreNewFeatures) const;
+
+ ClusterState& operator=(const ClusterState& other);
+ bool operator==(const ClusterState& other) const;
+ bool operator!=(const ClusterState& other) const;
+
+ uint32_t getVersion() const { return _version; }
+ /**
+ * Returns the smallest number above the highest node index found of the
+ * given type that is not down.
+ */
+ uint16_t getNodeCount(const NodeType& type) const;
+ uint16_t getDistributionBitCount() const { return _distributionBits; }
+ const State& getClusterState() const { return *_clusterState; }
+ const NodeState& getNodeState(const Node& node) const;
+ const vespalib::string& getDescription() const { return _description; }
+
+ void setVersion(uint32_t version) { _version = version; }
+ void setClusterState(const State& state);
+ void setNodeState(const Node& node, const NodeState& state);
+ void setDescription(const vespalib::stringref & s) { _description = s; }
+ void setDistributionBitCount(uint16_t count) { _distributionBits = count; }
+
+ virtual void print(std::ostream& out, bool verbose,
+ const std::string& indent) const;
+
+ void printStateGroupwise(std::ostream& out,
+ const Distribution&, bool verbose = false,
+ const std::string& indent = "") const;
+
+private:
+ void removeExtraElements();
+ void printStateGroupwise(std::ostream& out, const Group&, bool verbose,
+ const std::string& indent, bool rootGroup) const;
+
+};
+
+} // lib
+} // storage
+
diff --git a/vdslib/src/vespa/vdslib/state/diskstate.cpp b/vdslib/src/vespa/vdslib/state/diskstate.cpp
new file mode 100644
index 00000000000..2ce6db9e563
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/state/diskstate.cpp
@@ -0,0 +1,165 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/fastos/fastos.h>
+#include <vespa/vdslib/state/diskstate.h>
+
+#include <boost/lexical_cast.hpp>
+#include <vespa/vespalib/text/stringtokenizer.h>
+#include <vespa/document/util/stringutil.h>
+#include <vespa/log/log.h>
+#include <vespa/vespalib/util/exceptions.h>
+
+LOG_SETUP(".vdslib.diskstate");
+
+namespace storage {
+namespace lib {
+
+DiskState::DiskState()
+ : _state(0),
+ _description(""),
+ _capacity(1.0)
+{
+ setState(State::UP);
+}
+
+DiskState::DiskState(const State& state, const vespalib::stringref & description,
+ double capacity)
+ : _state(0),
+ _description(description),
+ _capacity(1.0)
+{
+ setState(state);
+ setCapacity(capacity);
+}
+
+DiskState::DiskState(const vespalib::stringref & serialized)
+ : _state(&State::UP),
+ _description(""),
+ _capacity(1.0)
+{
+ vespalib::StringTokenizer st(serialized, " \t\f\r\n");
+ st.removeEmptyTokens();
+ for (vespalib::StringTokenizer::Iterator it = st.begin();
+ it != st.end(); ++it)
+ {
+ std::string::size_type index = it->find(':');
+ if (index == std::string::npos) {
+ throw vespalib::IllegalArgumentException(
+ "Token " + *it + " does not contain ':': " + serialized,
+ VESPA_STRLOC);
+ }
+ std::string key = it->substr(0, index);
+ std::string value = it->substr(index + 1);
+ if (key.size() > 0) switch (key[0]) {
+ case 's':
+ if (key.size() > 1) break;
+ setState(State::get(value));
+ continue;
+ case 'c':
+ if (key.size() > 1) break;
+ try{
+ setCapacity(boost::lexical_cast<double>(value));
+ } catch (...) {
+ throw vespalib::IllegalArgumentException(
+ "Illegal disk capacity '" + value + "'. Capacity "
+ "must be a positive floating point number",
+ VESPA_STRLOC);
+ }
+ case 'm':
+ if (key.size() > 1) break;
+ _description = document::StringUtil::unescape(value);
+ continue;
+ default:
+ break;
+ }
+ LOG(debug, "Unknown key %s in diskstate. Ignoring it, assuming it's a "
+ "new feature from a newer version than ourself: %s",
+ key.c_str(), serialized.c_str());
+ }
+
+}
+
+void
+DiskState::serialize(vespalib::asciistream & out, const vespalib::stringref & prefix,
+ bool includeDescription, bool useOldFormat) const
+{
+ // Always give node state if not part of a system state
+ // to prevent empty serialization
+ bool empty = true;
+ if (*_state != State::UP || prefix.size() == 0) {
+ if (useOldFormat && prefix.size() > 0) {
+ out << prefix.substr(0, prefix.size() - 1)
+ << ":" << _state->serialize();
+ } else {
+ out << prefix << "s:" << _state->serialize();
+ }
+ empty = false;
+ }
+ if (_capacity != 1.0) {
+ if (empty) { empty = false; } else { out << ' '; }
+ out << prefix << "c:" << _capacity;
+ }
+ if (includeDescription && _description.size() > 0) {
+ if (empty) { empty = false; } else { out << ' '; }
+ out << prefix << "m:"
+ << document::StringUtil::escape(_description, ' ');
+ }
+}
+
+
+void
+DiskState::setState(const State& state)
+{
+ if (!state.validDiskState()) {
+ throw vespalib::IllegalArgumentException(
+ "State " + state.toString() + " is not a valid disk state.",
+ VESPA_STRLOC);
+ }
+ _state = &state;
+}
+
+void
+DiskState::setCapacity(double capacity)
+{
+ if (capacity < 0) {
+ throw vespalib::IllegalArgumentException(
+ "Negative capacity makes no sense.", VESPA_STRLOC);
+ }
+ _capacity = capacity;
+}
+
+void
+DiskState::print(std::ostream& out, bool verbose,
+ const std::string& indent) const
+{
+ (void) indent;
+ if (verbose) {
+ out << "DiskState(" << *_state;
+ } else {
+ out << _state->serialize();
+ }
+ if (_capacity != 1.0) {
+ out << (verbose ? ", capacity " : ", c ") << _capacity;
+ }
+ if (_description.size() > 0) {
+ out << ": " << _description;
+ }
+ if (verbose) {
+ out << ")";
+ }
+}
+
+bool
+DiskState::operator==(const DiskState& other) const
+{
+ return (_state == other._state && _capacity == other._capacity);
+}
+
+bool
+DiskState::operator!=(const DiskState& other) const
+{
+ return (_state != other._state || _capacity != other._capacity);
+}
+
+} // lib
+} // storage
diff --git a/vdslib/src/vespa/vdslib/state/diskstate.h b/vdslib/src/vespa/vdslib/state/diskstate.h
new file mode 100644
index 00000000000..9a6855efedd
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/state/diskstate.h
@@ -0,0 +1,50 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+/**
+ * @class vdslib::DiskState
+ *
+ * Defines the state a given disk can have.
+ */
+#pragma once
+
+#include <vespa/document/util/printable.h>
+#include <vespa/vdslib/state/state.h>
+#include <vespa/vespalib/objects/floatingpointtype.h>
+
+namespace storage {
+namespace lib {
+
+class DiskState : public document::Printable {
+ const State* _state;
+ vespalib::string _description;
+ vespalib::Double _capacity;
+
+public:
+ typedef std::shared_ptr<const DiskState> CSP;
+ typedef std::shared_ptr<DiskState> SP;
+
+ DiskState();
+ DiskState(const State&, const vespalib::stringref & description = "",
+ double capacity = 1.0);
+ explicit DiskState(const vespalib::stringref & serialized);
+
+ void serialize(vespalib::asciistream & out, const vespalib::stringref & prefix = "",
+ bool includeReason = true, bool useOldFormat = false) const;
+
+ const State& getState() const { return *_state; }
+ vespalib::Double getCapacity() const { return _capacity; }
+ const vespalib::string& getDescription() const { return _description; }
+
+ void setState(const State& state);
+ void setCapacity(double capacity);
+ void setDescription(const vespalib::stringref & desc) { _description = desc; }
+
+ virtual void print(std::ostream& out, bool verbose,
+ const std::string& indent) const;
+ bool operator==(const DiskState& other) const;
+ bool operator!=(const DiskState& other) const;
+
+};
+
+} // lib
+} // storage
+
diff --git a/vdslib/src/vespa/vdslib/state/idealgroup.cpp b/vdslib/src/vespa/vdslib/state/idealgroup.cpp
new file mode 100644
index 00000000000..442d91f102b
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/state/idealgroup.cpp
@@ -0,0 +1,27 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#include <vespa/fastos/fastos.h>
+#include <vespa/vdslib/state/idealgroup.h>
+
+
+namespace storage {
+namespace lib {
+
+IdealGroup::IdealGroup(const Group& g, double score, double redundancy)
+ : _group(&g),
+ _score(score),
+ _redundancy(redundancy)
+{
+}
+
+void
+IdealGroup::print(std::ostream& out, bool verbose,
+ const std::string& indent) const {
+
+ out << indent << "\nredundancy : " << _redundancy << "\n";
+ out << indent << "score : " << _score << "\n";
+ out << indent << "group : \n" ;
+ _group->print(out, verbose, indent + " ");
+}
+
+} // lib
+} // storage
diff --git a/vdslib/src/vespa/vdslib/state/idealgroup.h b/vdslib/src/vespa/vdslib/state/idealgroup.h
new file mode 100644
index 00000000000..b0fb34d0269
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/state/idealgroup.h
@@ -0,0 +1,61 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+/**
+ * @class vdslib::IdealGroup
+ *
+ * Points to a Group object that has been picked for
+ * distribution with a given redundancy.
+ *
+ *
+ */
+#pragma once
+
+#include <vdslib/state/group.h>
+#include <vespa/vespalib/objects/floatingpointtype.h>
+
+namespace storage {
+namespace lib {
+
+class IdealGroup : public document::Printable
+{
+ const Group* _group;
+ double _score;
+ double _redundancy;
+
+public:
+ IdealGroup() {};
+
+ IdealGroup(const Group& group, double score, double redundancy);
+
+ virtual void print(std::ostream& out, bool verbose,
+ const std::string& indent) const;
+
+ double getRedundancy() const {return _redundancy;}
+
+ void setRedundancy(double redundancy) {_redundancy = redundancy;}
+
+ double getScore() const {return _score;}
+
+ static bool sortScore (IdealGroup ig1, IdealGroup ig2)
+ {
+ return (ig1._score<ig2._score);
+ }
+
+ static bool sortRedundancy (IdealGroup ig1, IdealGroup ig2)
+ {
+ return (ig1._redundancy<ig2._redundancy);
+ }
+
+ const std::vector<uint16_t>& getNodes() const
+ {
+ return _group->getNodes();
+ }
+
+ const Group& getGroup() const {
+ return *_group;
+ }
+
+};
+
+} // lib
+} // storage
+
diff --git a/vdslib/src/vespa/vdslib/state/node.cpp b/vdslib/src/vespa/vdslib/state/node.cpp
new file mode 100644
index 00000000000..bcaf3f5231e
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/state/node.cpp
@@ -0,0 +1,22 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/fastos/fastos.h>
+#include <vespa/vdslib/state/node.h>
+
+namespace storage {
+namespace lib {
+
+Node::Node(const NodeType& type, uint16_t index)
+ : _type(&type),
+ _index(index)
+{
+}
+
+void
+Node::print(vespalib::asciistream& as, const PrintProperties&) const
+{
+ as << *_type << '.' << _index;
+}
+
+} // lib
+} // storage
diff --git a/vdslib/src/vespa/vdslib/state/node.h b/vdslib/src/vespa/vdslib/state/node.h
new file mode 100644
index 00000000000..4b9718162ab
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/state/node.h
@@ -0,0 +1,41 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+/**
+ * @class vdslib::Node
+ *
+ * Refers to a single node in a VDS cluster.
+ */
+
+#pragma once
+
+#include <vespa/vespalib/util/printable.h>
+#include <vespa/vdslib/state/nodetype.h>
+
+namespace storage {
+namespace lib {
+
+class Node : public vespalib::AsciiPrintable {
+ const NodeType* _type;
+ uint16_t _index;
+
+public:
+ Node() : _type(&NodeType::STORAGE), _index(0) {}
+ Node(const NodeType& type, uint16_t index);
+
+ const NodeType& getType() const { return *_type; }
+ uint16_t getIndex() const { return _index; }
+
+ void print(vespalib::asciistream&, const PrintProperties&) const;
+
+ bool operator==(const Node& other) const
+ { return (other._index == _index && *other._type == *_type); }
+ bool operator!=(const Node& other) const
+ { return (other._index != _index || *other._type != *_type); }
+
+ bool operator<(const Node& n) const {
+ if (*_type != *n._type) return (*_type < *n._type);
+ return (_index < n._index);
+ }
+};
+
+} // lib
+} // storage
diff --git a/vdslib/src/vespa/vdslib/state/nodestate.cpp b/vdslib/src/vespa/vdslib/state/nodestate.cpp
new file mode 100644
index 00000000000..812da98a710
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/state/nodestate.cpp
@@ -0,0 +1,613 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/fastos/fastos.h>
+#include <vespa/vdslib/state/nodestate.h>
+
+#include <boost/lexical_cast.hpp>
+#include <vespa/vespalib/text/stringtokenizer.h>
+#include <vespa/document/util/stringutil.h>
+#include <vespa/log/log.h>
+#include <vespa/vespalib/util/exceptions.h>
+#include <vespa/vdslib/state/random.h>
+#include <sstream>
+#include <cmath>
+
+LOG_SETUP(".vdslib.nodestate");
+
+namespace storage {
+namespace lib {
+
+NodeState::NodeState()
+ : _type(0),
+ _state(0),
+ _description(""),
+ _capacity(1.0),
+ _reliability(1),
+ _initProgress(0.0),
+ _minUsedBits(16),
+ _diskStates(),
+ _anyDiskDown(false),
+ _startTimestamp(0)
+{
+ setState(State::UP);
+}
+
+NodeState::NodeState(const NodeType& type, const State& state,
+ const vespalib::stringref & description,
+ double capacity, uint16_t reliability)
+ : _type(&type),
+ _state(0),
+ _description(description),
+ _capacity(1.0),
+ _reliability(1),
+ _initProgress(0.0),
+ _minUsedBits(16),
+ _diskStates(),
+ _anyDiskDown(false),
+ _startTimestamp(0)
+{
+ setState(state);
+ if (type == NodeType::STORAGE) {
+ setCapacity(capacity);
+ setReliability(reliability);
+ }
+}
+
+namespace {
+ struct DiskData {
+ bool empty;
+ uint16_t diskIndex;
+ std::ostringstream ost;
+
+ DiskData() : empty(true), diskIndex(0), ost() {}
+
+ void addTo(std::vector<DiskState>& diskStates) {
+ if (!empty) {
+ while (diskIndex >= diskStates.size()) {
+ diskStates.push_back(DiskState(State::UP));
+ }
+ diskStates[diskIndex] = DiskState(ost.str());
+ empty = true;
+ ost.str("");
+ }
+ }
+ };
+}
+
+NodeState::NodeState(const vespalib::stringref & serialized, const NodeType* type)
+ : _type(type),
+ _state(&State::UP),
+ _description(),
+ _capacity(1.0),
+ _reliability(1),
+ _initProgress(0.0),
+ _minUsedBits(16),
+ _diskStates(),
+ _anyDiskDown(false),
+ _startTimestamp(0)
+{
+
+ vespalib::StringTokenizer st(serialized, " \t\f\r\n");
+ st.removeEmptyTokens();
+ DiskData diskData;
+ for (vespalib::StringTokenizer::Iterator it = st.begin();
+ it != st.end(); ++it)
+ {
+ std::string::size_type index = it->find(':');
+ if (index == std::string::npos) {
+ throw vespalib::IllegalArgumentException(
+ "Token " + *it + " does not contain ':': " + serialized,
+ VESPA_STRLOC);
+ }
+ std::string key = it->substr(0, index);
+ std::string value = it->substr(index + 1);
+ if (key.size() > 0) switch (key[0]) {
+ case 'b':
+ if (_type != 0 && *type != NodeType::STORAGE) break;
+ if (key.size() > 1) break;
+ try{
+ setMinUsedBits(boost::lexical_cast<uint32_t>(value));
+ } catch (...) {
+ throw vespalib::IllegalArgumentException(
+ "Illegal used bits '" + value + "'. Used bits "
+ "must be a positive integer ",
+ VESPA_STRLOC);
+ }
+ continue;
+ case 's':
+ if (key.size() > 1) break;
+ setState(State::get(value));
+ continue;
+ case 'c':
+ if (key.size() > 1) break;
+ if (_type != 0 && *type != NodeType::STORAGE) break;
+ try{
+ setCapacity(boost::lexical_cast<double>(value));
+ } catch (...) {
+ throw vespalib::IllegalArgumentException(
+ "Illegal capacity '" + value + "'. Capacity must be"
+ "a positive floating point number", VESPA_STRLOC);
+ }
+ continue;
+ case 'r':
+ if (_type != 0 && *type != NodeType::STORAGE) break;
+ if (key.size() > 1) break;
+ try{
+ setReliability(boost::lexical_cast<uint16_t>(value));
+ } catch (...) {
+ throw vespalib::IllegalArgumentException(
+ "Illegal reliability '" + value + "'. Reliability "
+ "must be a positive integer",
+ VESPA_STRLOC);
+ }
+ continue;
+ case 'i':
+ if (key.size() > 1) break;
+ try{
+ setInitProgress(boost::lexical_cast<double>(value));
+ } catch (...) {
+ throw vespalib::IllegalArgumentException(
+ "Illegal init progress '" + value + "'. Init "
+ "progress must be a floating point number from 0.0 "
+ "to 1.0",
+ VESPA_STRLOC);
+ }
+ continue;
+ case 't':
+ if (key.size() > 1) break;
+ try{
+ setStartTimestamp(boost::lexical_cast<uint64_t>(value));
+ } catch (...) {
+ throw vespalib::IllegalArgumentException(
+ "Illegal start timestamp '" + value + "'. Start "
+ "timestamp must be 0 or positive long.",
+ VESPA_STRLOC);
+ }
+ continue;
+ case 'm':
+ if (key.size() > 1) break;
+ _description = document::StringUtil::unescape(value);
+ continue;
+ case 'd':
+ {
+ if (_type != 0 && *type != NodeType::STORAGE) break;
+ if (key.size() == 1) {
+ uint16_t size(0);
+ try{
+ size = boost::lexical_cast<uint16_t>(value);
+ } catch (...) {
+ throw vespalib::IllegalArgumentException(
+ "Invalid disk count '" + value + "'. Need a "
+ "positive integer value", VESPA_STRLOC);
+ }
+ while (_diskStates.size() < size) {
+ _diskStates.push_back(DiskState(State::UP));
+ }
+ continue;
+ }
+ if (key[1] != '.') break;
+ uint16_t diskIndex;
+ std::string::size_type endp = key.find('.', 2);
+ std::string indexStr;
+ if (endp == std::string::npos) {
+ indexStr = key.substr(2);
+ } else {
+ indexStr = key.substr(2, endp - 2);
+ }
+ try{
+ diskIndex = boost::lexical_cast<uint16_t>(indexStr);
+ } catch (...) {
+ throw vespalib::IllegalArgumentException(
+ "Invalid disk index '" + indexStr + "'. Need a "
+ "positive integer value", VESPA_STRLOC);
+ }
+ if (diskIndex >= _diskStates.size()) {
+ std::ostringstream ost;
+ ost << "Cannot index disk " << diskIndex << " of "
+ << _diskStates.size();
+ throw vespalib::IllegalArgumentException(
+ ost.str(), VESPA_STRLOC);
+ }
+ if (diskData.diskIndex != diskIndex) {
+ diskData.addTo(_diskStates);
+ }
+ if (endp == std::string::npos) {
+ diskData.ost << " s:" << value;
+ } else {
+ diskData.ost << " " << key.substr(endp + 1) << ':' << value;
+ }
+ diskData.diskIndex = diskIndex;
+ diskData.empty = false;
+ continue;
+ }
+ default:
+ break;
+ }
+ LOG(debug, "Unknown key %s in nodestate. Ignoring it, assuming it's a "
+ "new feature from a newer version than ourself: %s",
+ key.c_str(), serialized.c_str());
+ }
+ diskData.addTo(_diskStates);
+ updateAnyDiskDownFlag();
+}
+
+void
+NodeState::updateAnyDiskDownFlag() {
+ bool anyDown = false;
+ for (uint32_t i=0; i<_diskStates.size(); ++i) {
+ if (_diskStates[i].getState() != State::UP) {
+ anyDown = true;
+ }
+ }
+ _anyDiskDown = anyDown;
+}
+
+namespace {
+ struct SeparatorPrinter {
+ mutable bool first;
+ SeparatorPrinter() : first(true) {}
+
+ void print(vespalib::asciistream & os) const {
+ if (first) {
+ first = false;
+ } else {
+ os << ' ';
+ }
+ }
+ };
+
+ vespalib::asciistream & operator<<(vespalib::asciistream & os, const SeparatorPrinter& sep)
+ {
+ sep.print(os);
+ return os;
+ }
+
+}
+
+void
+NodeState::serialize(vespalib::asciistream & out, const vespalib::stringref & prefix,
+ bool includeDescription, bool includeDiskDescription,
+ bool useOldFormat) const
+{
+ SeparatorPrinter sep;
+ // Always give node state if not part of a system state
+ // to prevent empty serialization
+ if (*_state != State::UP || prefix.size() == 0) {
+ out << sep << prefix << "s:";
+ if (useOldFormat && *_state == State::STOPPING) {
+ out << State::DOWN.serialize();
+ } else {
+ out << _state->serialize();
+ }
+ }
+ if (_capacity != 1.0) {
+ out << sep << prefix << "c:" << _capacity;
+ }
+ if (_reliability != 1) {
+ out << sep << prefix << "r:" << _reliability;
+ }
+ if (_minUsedBits != 16) {
+ out << sep << prefix << "b:" << _minUsedBits;
+ }
+ if (*_state == State::INITIALIZING && !useOldFormat) {
+ out << sep << prefix << "i:" << _initProgress;
+ }
+ if (_startTimestamp != 0) {
+ out << sep << prefix << "t:" << _startTimestamp;
+ }
+ if (_diskStates.size() > 0) {
+ out << sep << prefix << "d:" << _diskStates.size();
+ for (uint16_t i = 0; i < _diskStates.size(); ++i) {
+ vespalib::asciistream diskPrefix;
+ diskPrefix << prefix << "d." << i << ".";
+ vespalib::asciistream disk;
+ _diskStates[i].serialize(disk, diskPrefix.str(),
+ includeDiskDescription, useOldFormat);
+ if ( ! disk.str().empty()) {
+ out << " " << disk.str();
+ }
+ }
+ }
+ if (includeDescription && ! _description.empty()) {
+ out << sep << prefix << "m:"
+ << document::StringUtil::escape(_description, ' ');
+ }
+}
+
+const DiskState&
+NodeState::getDiskState(uint16_t index) const
+{
+ static const DiskState defaultState(State::UP);
+ if (_diskStates.size() == 0) return defaultState;
+ if (index >= _diskStates.size()) {
+ std::ostringstream ost;
+ ost << "Cannot get status of disk " << index << " of "
+ << _diskStates.size() << ".";
+ throw vespalib::IllegalArgumentException(ost.str(), VESPA_STRLOC);
+ }
+ return _diskStates[index];
+}
+
+void
+NodeState::setState(const State& state)
+{
+ if (_type != 0) {
+ // We don't know whether you want to store reported, wanted or
+ // current node state, so we must accept any.
+ if (!state.validReportedNodeState(*_type)
+ && !state.validWantedNodeState(*_type))
+ {
+ throw vespalib::IllegalArgumentException(
+ state.toString(true) + " is not a legal "
+ + _type->toString() + " state", VESPA_STRLOC);
+ }
+ }
+ _state = &state;
+}
+
+void
+NodeState::setMinUsedBits(uint32_t usedBits) {
+ if (usedBits < 1 || usedBits > 58) {
+ std::ostringstream ost;
+ ost << "Illegal used bits '" << usedBits << "'. Minimum used bits"
+ "must be an integer > 0 and < 59.";
+ throw vespalib::IllegalArgumentException(ost.str(), VESPA_STRLOC);
+ }
+
+ _minUsedBits = usedBits;
+}
+
+void
+NodeState::setCapacity(vespalib::Double capacity)
+{
+ if (capacity < 0) {
+ std::ostringstream ost;
+ ost << "Illegal capacity '" << capacity << "'. Capacity "
+ "must be a positive floating point number";
+ throw vespalib::IllegalArgumentException(ost.str(), VESPA_STRLOC);
+ }
+ if (_type != 0 && *_type != NodeType::STORAGE) {
+ throw vespalib::IllegalArgumentException(
+ "Capacity only make sense for storage nodes.", VESPA_STRLOC);
+ }
+ _capacity = capacity;
+}
+
+void
+NodeState::setReliability(uint16_t reliability)
+{
+ if (reliability == 0) {
+ std::ostringstream ost;
+ ost << "Illegal reliability '" << reliability << "'. Reliability "
+ "must be a positive integer.";
+ throw vespalib::IllegalArgumentException(ost.str(), VESPA_STRLOC);
+ }
+ if (_type != 0 && *_type != NodeType::STORAGE) {
+ throw vespalib::IllegalArgumentException(
+ "Reliability only make sense for storage nodes.", VESPA_STRLOC);
+ }
+ _reliability = reliability;
+}
+
+void
+NodeState::setInitProgress(vespalib::Double initProgress)
+{
+ if (initProgress < 0 || initProgress > 1.0) {
+ std::ostringstream ost;
+ ost << "Illegal init progress '" << initProgress << "'. Init progress "
+ "must be a floating point number from 0.0 to 1.0";
+ throw vespalib::IllegalArgumentException(ost.str(), VESPA_STRLOC);
+ }
+ _initProgress = initProgress;
+}
+
+void
+NodeState::setStartTimestamp(uint64_t startTimestamp)
+{
+ _startTimestamp = startTimestamp;
+}
+
+void
+NodeState::setDiskCount(uint16_t count)
+{
+ while (_diskStates.size() > count) {
+ _diskStates.pop_back();
+ }
+ _diskStates.reserve(count);
+ while (_diskStates.size() < count) {
+ _diskStates.push_back(DiskState(State::UP));
+ }
+ updateAnyDiskDownFlag();
+}
+
+void
+NodeState::setDiskState(uint16_t index, const DiskState& state)
+{
+ if (index >= _diskStates.size()) {
+ throw vespalib::IllegalArgumentException(
+ vespalib::make_string("Can't set state of disk %u of %u.",
+ index, (uint32_t) _diskStates.size()),
+ VESPA_STRLOC);
+ }
+ _diskStates[index] = state;
+ updateAnyDiskDownFlag();
+}
+
+void
+NodeState::print(std::ostream& out, bool verbose,
+ const std::string& indent) const
+{
+ if (!verbose) {
+ vespalib::asciistream tmp;
+ serialize(tmp);
+ out << tmp.str();
+ return;
+ }
+ _state->print(out, verbose, indent);
+ if (_capacity != 1.0) {
+ out << ", capacity " << _capacity;
+ }
+ if (_reliability != 1) {
+ out << ", reliability " << _reliability;
+ }
+ if (_minUsedBits != 16) {
+ out << ", minimum used bits " << _minUsedBits;
+ }
+ if (*_state == State::INITIALIZING) {
+ out << ", init progress " << _initProgress;
+ }
+ if (_startTimestamp != 0) {
+ out << ", start timestamp " << _startTimestamp;
+ }
+ if (_diskStates.size() > 0) {
+ bool printedHeader = false;
+ for (uint32_t i=0; i<_diskStates.size(); ++i) {
+ if (_diskStates[i] != DiskState(State::UP)) {
+ if (!printedHeader) {
+ out << ",";
+ printedHeader = true;
+ }
+ out << " Disk " << i << "(";
+ _diskStates[i].print(out, false, indent);
+ out << ")";
+ }
+ }
+ }
+ if (_description.size() > 0) {
+ out << ": " << _description;
+ }
+}
+
+bool
+NodeState::operator==(const NodeState& other) const
+{
+ if (_state != other._state ||
+ _capacity != other._capacity ||
+ _reliability != other._reliability ||
+ _minUsedBits != other._minUsedBits ||
+ _startTimestamp != other._startTimestamp ||
+ (*_state == State::INITIALIZING
+ && _initProgress != other._initProgress))
+ {
+ return false;
+ }
+ for (uint32_t i=0, n=std::max(_diskStates.size(), other._diskStates.size());
+ i < n; ++i)
+ {
+ if (getDiskState(i) != other.getDiskState(i)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool
+NodeState::similarTo(const NodeState& other) const
+{
+ if (_state != other._state ||
+ _capacity != other._capacity ||
+ _reliability != other._reliability ||
+ _minUsedBits != other._minUsedBits ||
+ _startTimestamp < other._startTimestamp)
+ {
+ return false;
+ }
+ if (*_state == State::INITIALIZING) {
+ double limit = getListingBucketsInitProgressLimit();
+ bool below1 = (_initProgress < limit);
+ bool below2 = (other._initProgress < limit);
+ if (below1 != below2) {
+ return false;
+ }
+ }
+ for (uint32_t i=0, n=std::max(_diskStates.size(), other._diskStates.size());
+ i < n; ++i)
+ {
+ if (getDiskState(i) != other.getDiskState(i)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void
+NodeState::verifySupportForNodeType(const NodeType& type) const
+{
+ if (_type != 0 && *_type == type) return;
+ if (!_state->validReportedNodeState(type)
+ && !_state->validWantedNodeState(type))
+ {
+ throw vespalib::IllegalArgumentException("State " + _state->toString()
+ + " does not fit a node of type " + type.toString(),
+ VESPA_STRLOC);
+ }
+ if (type == NodeType::DISTRIBUTOR && _capacity != 1.0) {
+ throw vespalib::IllegalArgumentException("Capacity should not be "
+ "set for a distributor node.", VESPA_STRLOC);
+ }
+ if (type == NodeType::DISTRIBUTOR && _reliability != 1) {
+ throw vespalib::IllegalArgumentException("Reliability should not be "
+ "set for a distributor node.", VESPA_STRLOC);
+ }
+}
+
+std::string
+NodeState::getTextualDifference(const NodeState& other) const {
+ std::ostringstream source;
+ std::ostringstream target;
+
+ if (_state != other._state) {
+ source << ", " << *_state;
+ target << ", " << *other._state;
+ }
+ if (_capacity != other._capacity) {
+ source << ", capacity " << _capacity;
+ target << ", capacity " << other._capacity;
+ }
+ if (_reliability != other._reliability) {
+ source << ", reliability " << _reliability;
+ target << ", reliability " << other._reliability;
+ }
+ if (_minUsedBits != other._minUsedBits) {
+ source << ", minUsedBits " << _minUsedBits;
+ target << ", minUsedBits " << _minUsedBits;
+ }
+ if (_initProgress != other._initProgress) {
+ if (_state == &State::INITIALIZING) {
+ source << ", init progress " << _initProgress;
+ }
+ if (other._state == &State::INITIALIZING) {
+ target << ", init progress " << other._initProgress;
+ }
+ }
+ if (_startTimestamp != other._startTimestamp) {
+ source << ", start timestamp " << _startTimestamp;
+ target << ", start timestamp " << other._startTimestamp;
+ }
+
+ if (_diskStates.size() != other._diskStates.size()) {
+ source << ", " << _diskStates.size() << " disks";
+ target << ", " << other._diskStates.size() << " disks";
+ } else {
+ for (uint32_t i=0; i<_diskStates.size(); ++i) {
+ if (_diskStates[i] != other._diskStates[i]) {
+ source << ", disk " << i << _diskStates[i];
+ target << ", disk " << i << other._diskStates[i];
+ }
+ }
+ }
+
+ if (source.str().length() < 2 || target.str().length() < 2) {
+ return "no change";
+ }
+
+ std::ostringstream total;
+ total << source.str().substr(2) << " to " << target.str().substr(2);
+ if (other._description != _description) {
+ total << " (" << other._description << ")";
+ }
+ return total.str();
+}
+
+} // lib
+} // storage
diff --git a/vdslib/src/vespa/vdslib/state/nodestate.h b/vdslib/src/vespa/vdslib/state/nodestate.h
new file mode 100644
index 00000000000..5cfd5d7edc6
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/state/nodestate.h
@@ -0,0 +1,108 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+/**
+ * @class vdslib::NodeState
+ *
+ * Defines a NodeState object that defines the state of a node.
+ *
+ * If the object knows of the node type of the node it belongs to, it will
+ * verify that changes made makes sense for that type of node. To not alter
+ * interface too much and allow empty constructor, this nodetype is optional.
+ */
+#pragma once
+
+#include <string>
+#include <vector>
+#include <vespa/document/bucket/bucketidfactory.h>
+#include <vespa/document/util/xmlserializable.h>
+#include <vespa/vdslib/state/diskstate.h>
+#include <vespa/vdslib/state/state.h>
+#include <vespa/vdslib/state/random.h>
+
+namespace storage {
+namespace lib {
+
+class NodeState : public document::Printable
+{
+ const NodeType* _type;
+ const State* _state;
+ vespalib::string _description;
+ vespalib::Double _capacity;
+ uint16_t _reliability;
+ vespalib::Double _initProgress;
+ uint32_t _minUsedBits;
+ std::vector<DiskState> _diskStates;
+ bool _anyDiskDown;
+ uint64_t _startTimestamp;
+
+ void updateAnyDiskDownFlag();
+
+public:
+ typedef std::shared_ptr<const NodeState> CSP;
+ typedef std::shared_ptr<NodeState> SP;
+ typedef std::unique_ptr<NodeState> UP;
+
+ static double getListingBucketsInitProgressLimit() { return 0.01; }
+
+ NodeState();
+ NodeState(const NodeType& nodeType, const State&,
+ const vespalib::stringref & description = "",
+ double capacity = 1.0, uint16_t reliability = 1);
+ /** Set type if you want to verify that content fit with the given type. */
+ NodeState(const vespalib::stringref & serialized, const NodeType* nodeType = 0);
+ virtual ~NodeState() {}
+
+ /**
+ * Setting prefix to something implies using this function to write a
+ * part of the system state. Don't set prefix if you want to be able to
+ * recreate the nodestate with NodeState(string) function.
+ */
+ void serialize(vespalib::asciistream & out, const vespalib::stringref & prefix = "",
+ bool includeDescription = true,
+ bool includeDiskDescription = false,
+ bool useOldFormat = false) const;
+
+ const State& getState() const { return *_state; }
+ vespalib::Double getCapacity() const { return _capacity; }
+ uint32_t getMinUsedBits() const { return _minUsedBits; }
+ uint16_t getReliability() const { return _reliability; }
+ vespalib::Double getInitProgress() const { return _initProgress; }
+ const vespalib::string& getDescription() const { return _description; }
+ uint64_t getStartTimestamp() const { return _startTimestamp; }
+
+ bool isAnyDiskDown() const { return _anyDiskDown; }
+ uint16_t getDiskCount() const { return _diskStates.size(); }
+ const DiskState& getDiskState(uint16_t index) const;
+
+ void setState(const State& state);
+ void setCapacity(vespalib::Double capacity);
+ void setMinUsedBits(uint32_t usedBits);
+ void setReliability(uint16_t reliability);
+ void setInitProgress(vespalib::Double initProgress);
+ void setStartTimestamp(uint64_t startTimestamp);
+ void setDescription(const vespalib::stringref & desc) { _description = desc; }
+
+ void setDiskCount(uint16_t count);
+ void setDiskState(uint16_t index, const DiskState&);
+
+ virtual void print(std::ostream& out, bool verbose,
+ const std::string& indent) const;
+ bool operator==(const NodeState& other) const;
+ bool operator!=(const NodeState& other) const
+ { return !(operator==(other)); }
+ bool similarTo(const NodeState& other) const;
+
+ /**
+ * Verify that the contents of this object fits with the given nodetype.
+ * This is a noop if nodetype was given in constructor of this object.
+ *
+ * @throws vespalib::IllegalStateException if not fitting.
+ */
+ void verifySupportForNodeType(const NodeType& type) const;
+
+ std::string getTextualDifference(const NodeState& other) const;
+
+};
+
+} // lib
+} // storage
+
diff --git a/vdslib/src/vespa/vdslib/state/nodetype.cpp b/vdslib/src/vespa/vdslib/state/nodetype.cpp
new file mode 100644
index 00000000000..e12c1e00714
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/state/nodetype.cpp
@@ -0,0 +1,36 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/fastos/fastos.h>
+#include <vespa/vdslib/state/nodetype.h>
+
+#include <vespa/vespalib/util/exceptions.h>
+
+namespace storage {
+namespace lib {
+
+// WARNING: Because static initialization happen in random order, the State
+// class use these enum values directly during static initialization since
+// these objects may yet not exist. Update in State if you change this.
+const NodeType NodeType::STORAGE("storage", 0);
+const NodeType NodeType::DISTRIBUTOR("distributor", 1);
+
+const NodeType&
+NodeType::get(const vespalib::stringref & serialized)
+{
+ if (serialized == STORAGE._name) {
+ return STORAGE;
+ }
+ if (serialized == DISTRIBUTOR._name) {
+ return DISTRIBUTOR;
+ }
+ throw vespalib::IllegalArgumentException(
+ "Unknown node type " + serialized + " given.", VESPA_STRLOC);
+}
+
+NodeType::NodeType(const vespalib::stringref & name, uint16_t enumValue)
+ : _enumValue(enumValue), _name(name)
+{
+}
+
+} // lib
+} // storage
diff --git a/vdslib/src/vespa/vdslib/state/nodetype.h b/vdslib/src/vespa/vdslib/state/nodetype.h
new file mode 100644
index 00000000000..04c39a1c610
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/state/nodetype.h
@@ -0,0 +1,54 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+/**
+ * @class vdslib::NodeType
+ *
+ * Sets what type of node we're talking about. This class exist so we don't need
+ * to duplicate all functions for storage and distributor nodes in states, and
+ * to avoid using a bool for type. This also makes it more easily expandable
+ * with other node types.
+ */
+#pragma once
+
+#include <vespa/vespalib/stllike/asciistream.h>
+#include <stdint.h>
+#include <iostream>
+
+namespace storage {
+namespace lib {
+
+class NodeType {
+ typedef vespalib::asciistream asciistream;
+ uint16_t _enumValue;
+ vespalib::string _name;
+
+ NodeType(const vespalib::stringref & name, uint16_t enumValue);
+
+public:
+ static const NodeType DISTRIBUTOR;
+ static const NodeType STORAGE;
+
+ /** Throws vespalib::IllegalArgumentException if invalid state given. */
+ static const NodeType& get(const vespalib::stringref & serialized);
+ const vespalib::string& serialize() const { return _name; }
+
+ operator uint16_t() const { return _enumValue; }
+
+ const vespalib::string & toString() const { return _name; }
+ friend std::ostream & operator << (std::ostream & os, const NodeType & n) {
+ return os << n.toString();
+ }
+ friend asciistream & operator << (asciistream & os, const NodeType & n) {
+ return os << n.toString();
+ }
+
+ bool operator==(const NodeType& other) const { return (&other == this); }
+ bool operator!=(const NodeType& other) const { return (&other != this); }
+
+ bool operator<(const NodeType& other) const {
+ return (&other == this ? false : *this == NodeType::DISTRIBUTOR);
+ }
+};
+
+} // lib
+} // storage
+
diff --git a/vdslib/src/vespa/vdslib/state/random.h b/vdslib/src/vespa/vdslib/state/random.h
new file mode 100644
index 00000000000..1cd0f517cf7
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/state/random.h
@@ -0,0 +1,35 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#pragma once
+
+#include <vespa/vespalib/util/random.h>
+
+namespace storage {
+namespace lib {
+
+/**
+ * Random number generator. Compatible with java.util.Random
+ * Calls PRNG from vespalib, but throws away the first number generated.
+ */
+class RandomGen : public vespalib::RandomGen{
+public:
+ RandomGen(int32_t seed) : vespalib::RandomGen(seed) {
+ nextDouble();
+ };
+
+ /**
+ * Construct a random number generator with an auto-generated seed
+ */
+ RandomGen() : vespalib::RandomGen() {}
+
+ /**
+ * Reset the seed
+ */
+ void setSeed(int32_t seed) {
+ vespalib::RandomGen::setSeed(seed);
+ nextDouble();
+ }
+};
+
+} // lib
+} // storage
+
diff --git a/vdslib/src/vespa/vdslib/state/state.cpp b/vdslib/src/vespa/vdslib/state/state.cpp
new file mode 100644
index 00000000000..67c77196e59
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/state/state.cpp
@@ -0,0 +1,87 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/fastos/fastos.h>
+#include <vespa/vdslib/state/state.h>
+
+#include <vespa/vespalib/util/exceptions.h>
+
+namespace storage {
+namespace lib {
+
+const State State::UNKNOWN("Unknown", "-", 0,
+ false, true, true, false, false, false);
+const State State::MAINTENANCE("Maintenance", "m", 1,
+ false, false, false, true, true, false);
+const State State::DOWN("Down", "d", 2,
+ true, false, false, true, true, true);
+const State State::STOPPING("Stopping", "s", 3,
+ false, true, true, false, false, true);
+const State State::INITIALIZING("Initializing", "i", 4,
+ false, true, true, false, false, true);
+const State State::RETIRED("Retired", "r", 5,
+ false, false, false, true, true, false);
+const State State::UP("Up", "u", 6,
+ true, true, true, true, true, true);
+
+const State&
+State::get(const vespalib::stringref & serialized)
+{
+ if (serialized.size() == 1) switch(serialized[0]) {
+ case '-': return UNKNOWN;
+ case 'm': return MAINTENANCE;
+ case 'd': return DOWN;
+ case 's': return STOPPING;
+ case 'i': return INITIALIZING;
+ case 'r': return RETIRED;
+ case 'u': return UP;
+ default: break;
+ }
+ throw vespalib::IllegalArgumentException(
+ "Unknown state " + serialized + " given.", VESPA_STRLOC);
+}
+
+State::State(const vespalib::stringref & name, const vespalib::stringref & serialized,
+ uint8_t rank, bool validDisk,
+ bool validDistributorReported, bool validStorageReported,
+ bool validDistributorWanted, bool validStorageWanted,
+ bool validCluster)
+ : _name(name),
+ _serialized(serialized),
+ _rankValue(rank),
+ _validDiskState(validDisk),
+ _validReportedNodeState(2),
+ _validWantedNodeState(2),
+ _validClusterState(validCluster)
+{
+ // Since this is static initialization and NodeType is not necessarily
+ // created yet, use these enum values.
+ uint32_t storage = 0;
+ uint32_t distributor = 1;
+ _validReportedNodeState[storage] = validStorageReported;
+ _validReportedNodeState[distributor] = validDistributorReported;
+ _validWantedNodeState[storage] = validStorageWanted;
+ _validWantedNodeState[distributor] = validDistributorWanted;
+}
+
+State::~State()
+{
+}
+
+void
+State::print(std::ostream& out, bool verbose, const std::string& indent) const
+{
+ (void) indent;
+ out << (verbose ? _name : _serialized);
+}
+
+bool
+State::oneOf(const char* states) const
+{
+ for (const char* c = states; *c != '\0'; ++c) {
+ if (*c == _serialized[0]) return true;
+ }
+ return false;
+}
+
+} // lib
+} // storage
diff --git a/vdslib/src/vespa/vdslib/state/state.h b/vdslib/src/vespa/vdslib/state/state.h
new file mode 100644
index 00000000000..f42402f687b
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/state/state.h
@@ -0,0 +1,88 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+/**
+ * @class vdslib::State
+ *
+ * Defines legal states for various uses. Split this into its own class such
+ * that we can easily see what states are legal to use in what situations.
+ * They double as disk states and node states nodes report they are in, and
+ * wanted states set external sources.
+ */
+#pragma once
+
+#include <vespa/vespalib/util/printable.h>
+#include <vespa/vespalib/stllike/string.h>
+#include <vespa/vdslib/state/nodetype.h>
+#include <vector>
+
+namespace storage {
+namespace lib {
+
+class State : public vespalib::Printable {
+ vespalib::string _name;
+ vespalib::string _serialized;
+ uint8_t _rankValue;
+ bool _validDiskState;
+ std::vector<bool> _validReportedNodeState;
+ std::vector<bool> _validWantedNodeState;
+ bool _validClusterState;
+
+ State(const State&);
+ State(const vespalib::stringref & name, const vespalib::stringref & serialized,
+ uint8_t rank, bool validDisk,
+ bool validDistributorReported, bool validStorageReported,
+ bool validDistributorWanted, bool validStorageWanted,
+ bool validCluster);
+ ~State();
+
+ State& operator=(const State&);
+
+public:
+ static const State UNKNOWN;
+ static const State MAINTENANCE;
+ static const State DOWN;
+ static const State STOPPING;
+ static const State INITIALIZING;
+ static const State RETIRED;
+ static const State UP;
+
+ /** Throws vespalib::IllegalArgumentException if invalid state given. */
+ static const State& get(const vespalib::stringref & serialized);
+ const vespalib::string& serialize() const { return _serialized; }
+
+ bool validDiskState() const { return _validDiskState; }
+ bool validReportedNodeState(const NodeType& node) const
+ { return _validReportedNodeState[node]; }
+ bool validWantedNodeState(const NodeType& node) const
+ { return _validWantedNodeState[node]; }
+ bool validClusterState() const { return _validClusterState; }
+
+ bool maySetWantedStateForThisNodeState(const State& wantedState) const
+ { return (wantedState._rankValue <= _rankValue); }
+
+ /**
+ * Get a string that represents a more human readable version of
+ * the state than what can be provided through the single-character
+ * serialized representation.
+ *
+ * Example: State::RETIRED.getName() -> "Retired"
+ */
+ const vespalib::string& getName() const noexcept {
+ return _name;
+ }
+
+ virtual void print(std::ostream& out, bool verbose,
+ const std::string& indent) const;
+ bool operator==(const State& other) const { return (&other == this); }
+ bool operator!=(const State& other) const { return (&other != this); }
+
+ /**
+ * Utility function to check whether this state is one of the given
+ * states, given as the single character they are serialized as.
+ * For instance, "um" will check if this state is up or maintenance.
+ */
+ bool oneOf(const char* states) const;
+};
+
+} // lib
+} // storage
+
diff --git a/vdslib/src/vespa/vdslib/thread/.gitignore b/vdslib/src/vespa/vdslib/thread/.gitignore
new file mode 100644
index 00000000000..5dae353d999
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/thread/.gitignore
@@ -0,0 +1,2 @@
+.depend
+Makefile
diff --git a/vdslib/src/vespa/vdslib/thread/CMakeLists.txt b/vdslib/src/vespa/vdslib/thread/CMakeLists.txt
new file mode 100644
index 00000000000..b5974b5392b
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/thread/CMakeLists.txt
@@ -0,0 +1,6 @@
+# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_library(vdslib_thread OBJECT
+ SOURCES
+ taskscheduler.cpp
+ DEPENDS
+)
diff --git a/vdslib/src/vespa/vdslib/thread/taskscheduler.cpp b/vdslib/src/vespa/vdslib/thread/taskscheduler.cpp
new file mode 100644
index 00000000000..ad37c4dd591
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/thread/taskscheduler.cpp
@@ -0,0 +1,223 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#include <vespa/fastos/fastos.h>
+#include <vespa/vdslib/thread/taskscheduler.h>
+
+#include <iostream>
+#include <vespa/log/log.h>
+#include <vespa/vespalib/util/exceptions.h>
+
+LOG_SETUP(".task.scheduler");
+
+namespace vdslib {
+
+uint64_t
+TaskScheduler::Watch::getTime() const
+{
+ struct timeval mytime;
+ gettimeofday(&mytime, 0);
+ return mytime.tv_sec * 1000llu + mytime.tv_usec / 1000;
+}
+
+TaskScheduler::TaskScheduler()
+ : _lock(),
+ _defaultWatch(),
+ _watch(&_defaultWatch),
+ _tasks(),
+ _currentRunningTasks(),
+ _taskCounter(0)
+{
+}
+
+bool TaskScheduler::onStop()
+{
+ vespalib::MonitorGuard guard(_lock);
+ guard.broadcast();
+ return true;
+}
+
+TaskScheduler::~TaskScheduler()
+{
+ stop();
+ {
+ vespalib::MonitorGuard guard(_lock);
+ guard.broadcast();
+ }
+ join();
+ for (TaskMap::iterator it = _tasks.begin(); it != _tasks.end(); ++it) {
+ TaskVector & v(it->second);
+ for (TaskVector::iterator it2 = v.begin(); it2 != v.end(); ++it2) {
+ delete *it2;
+ }
+ }
+}
+
+void
+TaskScheduler::add(Task::UP task)
+{
+ vespalib::MonitorGuard guard(_lock);
+ std::vector<Task*>& tasks(_tasks[_watch->getTime()]);
+ tasks.push_back(task.release());
+ guard.broadcast();
+}
+
+void
+TaskScheduler::addRelative(Task::UP task, Time timeDiff)
+{
+ vespalib::MonitorGuard guard(_lock);
+ std::vector<Task*>& tasks(_tasks[_watch->getTime() + timeDiff]);
+ tasks.push_back(task.release());
+ guard.broadcast();
+}
+
+void
+TaskScheduler::addAbsolute(Task::UP task, Time time)
+{
+ vespalib::MonitorGuard guard(_lock);
+ std::vector<Task*>& tasks(_tasks[time]);
+ tasks.push_back(task.release());
+ guard.broadcast();
+}
+
+namespace {
+ template<typename T>
+ bool contains(const std::vector<T>& source, const T& element) {
+ for (size_t i = 0, n = source.size(); i<n; ++i) {
+ if (source[i] == element) return true;
+ }
+ return false;
+ }
+
+ template<typename T>
+ void erase(std::vector<T>& source, const T& element) {
+ std::vector<T> result;
+ result.reserve(source.size());
+ for (size_t i = 0, n = source.size(); i<n; ++i) {
+ if (source[i] != element) result.push_back(source[i]);
+ }
+ result.swap(source);
+ }
+}
+
+void
+TaskScheduler::remove(Task* task)
+{
+ vespalib::MonitorGuard guard(_lock);
+ while (contains(_currentRunningTasks, task)) {
+ guard.wait();
+ }
+ for (TaskMap::iterator it = _tasks.begin(); it != _tasks.end();) {
+ if (contains(it->second, task)) {
+ erase(it->second, task);
+ if (it->second.size() == 0) _tasks.erase(it);
+ delete task;
+ break;
+ }
+ ++it;
+ }
+}
+
+void
+TaskScheduler::setWatch(const Watch& watch)
+{
+ vespalib::MonitorGuard guard(_lock);
+ _watch = &watch;
+}
+
+TaskScheduler::Time
+TaskScheduler::getTime() const
+{
+ vespalib::MonitorGuard guard(_lock);
+ return _watch->getTime();
+}
+
+uint64_t
+TaskScheduler::getTaskCounter() const
+{
+ vespalib::MonitorGuard guard(_lock);
+ return _taskCounter;
+}
+
+void
+TaskScheduler::waitForTaskCounterOfAtLeast(uint64_t taskCounter,
+ uint64_t timeout) const
+{
+ vespalib::MonitorGuard guard(_lock);
+ uint64_t currentTime = _defaultWatch.getTime();
+ uint64_t endTime = currentTime + timeout;
+ while (_taskCounter < taskCounter) {
+ if (endTime <= currentTime) {
+ std::ostringstream ost;
+ ost << "Task scheduler not reached task counter of " << taskCounter
+ << " within timeout of " << timeout << " ms. Current task"
+ << " counter is " << _taskCounter;
+ throw vespalib::IllegalStateException(ost.str(), VESPA_STRLOC);
+ }
+ guard.wait(endTime - currentTime);
+ currentTime = _defaultWatch.getTime();
+ }
+}
+
+void
+TaskScheduler::waitUntilNoTasksRemaining(uint64_t timeout) const
+{
+ vespalib::MonitorGuard guard(_lock);
+ uint64_t currentTime = _defaultWatch.getTime();
+ uint64_t endTime = currentTime + timeout;
+ while (_tasks.size() > 0 || _currentRunningTasks.size() > 0) {
+ if (endTime <= currentTime) {
+ std::ostringstream ost;
+ ost << "Task scheduler still have tasks scheduled after timeout"
+ << " of " << timeout << " ms. There are " << _tasks.size()
+ << " entries in tasks map and " << _currentRunningTasks.size()
+ << " tasks currently scheduled to run.";
+ throw vespalib::IllegalStateException(ost.str(), VESPA_STRLOC);
+ }
+ guard.wait(endTime - currentTime);
+ currentTime = _defaultWatch.getTime();
+ }
+}
+
+void
+TaskScheduler::run()
+{
+ while (1) {
+ vespalib::MonitorGuard guard(_lock);
+ if (!running()) return;
+ Time time = _watch->getTime();
+ TaskMap::iterator next = _tasks.begin();
+ if (next == _tasks.end()) {
+ guard.wait();
+ continue;
+ }
+ if (next->first > time) {
+ guard.wait(next->first - time);
+ continue;
+ }
+ TaskVector taskList(next->second);
+ _currentRunningTasks.swap(next->second);
+ _tasks.erase(next);
+ guard.unlock();
+ for (size_t i=0; i<taskList.size(); ++i) {
+ int64_t result = taskList[i]->run(time);
+ if (result < 0) {
+ addAbsolute(Task::UP(taskList[i]),
+ time + (-1 * result));
+ } else if (result > 0) {
+ if (static_cast<Time>(result) <= time) {
+ taskList.push_back(taskList[i]);
+ } else {
+ addAbsolute(Task::UP(taskList[i]), result);
+ }
+ } else {
+ delete taskList[i];
+ }
+ }
+ vespalib::MonitorGuard guard2(_lock);
+ if (!running()) return;
+ _taskCounter += _currentRunningTasks.size();
+ _currentRunningTasks.clear();
+ guard2.broadcast();
+ }
+}
+
+} // vdslib
diff --git a/vdslib/src/vespa/vdslib/thread/taskscheduler.h b/vdslib/src/vespa/vdslib/thread/taskscheduler.h
new file mode 100644
index 00000000000..558ebd46c1e
--- /dev/null
+++ b/vdslib/src/vespa/vdslib/thread/taskscheduler.h
@@ -0,0 +1,105 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+/**
+ * \class vespalib::TaskScheduler
+ * \ingroup util
+ *
+ * \brief Class to register tasks in to get them run in a separate thread.
+ *
+ * Imported to vdslib as C++ document API needs an independent thread to run
+ * events in, as it was subject to errors to use FNET event thread. Converted
+ * this class used in storage API client code before.
+ */
+#pragma once
+
+#include <vespa/vespalib/util/document_runnable.h>
+#include <map>
+#include <memory>
+#include <vector>
+#include <vespa/vespalib/util/sync.h>
+
+namespace vdslib {
+
+class TaskScheduler : public document::Runnable
+{
+public:
+ typedef uint64_t Time;
+
+ struct Task {
+ typedef std::unique_ptr<Task> UP;
+ virtual ~Task() {}
+ /**
+ * Return 0 to unregister this task. Return a negative number to get a
+ * new callback in that many (times -1) milliseconds. Return a positive
+ * number to get a callback as soon as thread is available after that
+ * absolute point in time (in milliseconds). If returning current time
+ * or before, this task will be scheduled to be rerun immediately
+ * (after other already waiting tasks have had a chance to run).
+ * The current time for the scheduler is given to the task.
+ */
+ virtual int64_t run(Time) = 0;
+ };
+
+ /**
+ * If you want to fake time (useful for testing), implement your own watch
+ * for the scheduler to use.
+ */
+ struct Watch {
+ virtual ~Watch() {}
+ virtual Time getTime() const; // In ms since 1970
+ };
+
+ /** Creates a task scheduler. Remember to call start() to get it going. */
+ TaskScheduler();
+ ~TaskScheduler();
+
+ /** Register a task for immediate execution */
+ void add(Task::UP);
+
+ /** Register a task to be run in a given number of milliseconds from now */
+ void addRelative(Task::UP, Time);
+
+ /** Register a task to be run at given absolute time in milliseconds */
+ void addAbsolute(Task::UP, Time);
+
+ /**
+ * Removes a scheduled task from the scheduler. Note that this is
+ * currently not efficiently implemented but an exhaustive iteration of
+ * current tasks. Assuming number of tasks is small so this doesn't matter.
+ * If current task is running while this is called, function will block
+ * until it has completed before removing it. (To be safe if you want to
+ * delete task after.)
+ */
+ void remove(Task*);
+
+ /** Get the schedulers current time. */
+ Time getTime() const;
+
+ /** Set a custom watch to be used for this scheduler (Useful for testing) */
+ void setWatch(const Watch& watch);
+
+ /** Returns a number of current task */
+ uint64_t getTaskCounter() const;
+
+ /** Wait until a given number of tasks have been completed */
+ void waitForTaskCounterOfAtLeast(uint64_t taskCounter,
+ uint64_t timeout = 5000) const;
+
+ /** Call this to wait until no tasks are scheduled (Useful for testing) */
+ void waitUntilNoTasksRemaining(uint64_t timeout = 5000) const;
+
+private:
+ typedef std::vector<Task*> TaskVector;
+ typedef std::map<Time, TaskVector> TaskMap;
+ vespalib::Monitor _lock;
+ Watch _defaultWatch;
+ const Watch* _watch;
+ TaskMap _tasks;
+ TaskVector _currentRunningTasks;
+ uint64_t _taskCounter;
+
+ virtual void run();
+ virtual bool onStop();
+};
+
+} // vdslib
+