diff --git a/.classpath b/.classpath deleted file mode 100644 index fb565a5..0000000 --- a/.classpath +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/.gitignore b/.gitignore index f837fa2..9b2785d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ -bin/ -*.class -*MyTest.java -data/ -model/ +*.iml +/.idea +/.classpath +/.project +/target/ +src/test/dataset/test.predict +src/test/model.cnn diff --git a/.project b/.project deleted file mode 100644 index 8f8ffe9..0000000 --- a/.project +++ /dev/null @@ -1,17 +0,0 @@ - - - JavaCNN - - - - - - org.eclipse.jdt.core.javabuilder - - - - - - org.eclipse.jdt.core.javanature - - diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index 7341ab1..0000000 --- a/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,11 +0,0 @@ -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 -org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.7 -org.eclipse.jdt.core.compiler.debug.lineNumber=generate -org.eclipse.jdt.core.compiler.debug.localVariable=generate -org.eclipse.jdt.core.compiler.debug.sourceFile=generate -org.eclipse.jdt.core.compiler.problem.assertIdentifier=error -org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.7 diff --git a/dataset/readme.md b/dataset/readme.md deleted file mode 100644 index 3cda064..0000000 --- a/dataset/readme.md +++ /dev/null @@ -1,3 +0,0 @@ -

The dataset is part of MNIST from kaggle Digit Recognizer competition.

-

"train.format" is the train set, which has been binarized.

-

"test.format" is the test set, which has been binarized.

\ No newline at end of file diff --git a/dataset/test.predict b/dataset/test.predict deleted file mode 100644 index c6eb184..0000000 --- a/dataset/test.predict +++ /dev/null @@ -1,28000 +0,0 @@ -2 -0 -9 -9 -3 -7 -0 -3 -0 -3 -5 -7 -4 -0 -4 -0 -3 -1 -9 -0 -9 -1 -1 -5 -7 -4 -2 -7 -7 -7 -7 -5 -4 -2 -6 -2 -5 -5 -1 -6 -7 -7 -4 -9 -6 -7 -8 -2 -6 -7 -6 -8 -8 -3 -8 -2 -1 -2 -9 -0 -4 -1 -7 -0 -0 -0 -1 -9 -0 -1 -6 -5 -8 -8 -2 -8 -9 -9 -2 -3 -5 -9 -1 -0 -9 -2 -4 -3 -6 -7 -2 -0 -6 -6 -1 -4 -3 -9 -7 -4 -0 -3 -2 -0 -7 -3 -0 -5 -0 -9 -0 -0 -6 -1 -1 -7 -1 -1 -5 -3 -3 -7 -2 -8 -6 -3 -8 -7 -8 -4 -5 -5 -6 -0 -0 -0 -3 -1 -3 -0 -4 -3 -4 -5 -5 -8 -7 -7 -2 -8 -4 -3 -5 -6 -5 -1 -7 -5 -7 -8 -3 -0 -4 -5 -1 -2 -7 -6 -5 -0 -2 -7 -9 -6 -1 -3 -7 -4 -1 -2 -4 -2 -5 -2 -4 -9 -2 -1 -6 -0 -6 -1 -4 -2 -6 -0 -9 -7 -6 -9 -1 -9 -0 -5 -9 -0 -8 -4 -6 -2 -0 -9 -3 -6 -7 -2 -1 -6 -3 -4 -2 -3 -1 -3 -2 -8 -4 -6 -1 -0 -0 -4 -9 -1 -7 -3 -2 -2 -8 -6 -8 -6 -2 -8 -5 -5 -9 -8 -3 -8 -9 -7 -1 -3 -8 -4 -5 -1 -4 -3 -6 -3 -3 -5 -7 -0 -6 -8 -5 -1 -6 -0 -6 -3 -9 -9 -1 -5 -8 -4 -0 -9 -2 -0 -5 -3 -7 -8 -9 -9 -5 -9 -7 -9 -9 -6 -3 -0 -3 -3 -6 -9 -8 -2 -6 -2 -7 -1 -4 -5 -8 -5 -9 -0 -0 -3 -8 -4 -1 -5 -9 -1 -1 -9 -8 -4 -5 -1 -5 -7 -6 -3 -1 -3 -0 -9 -0 -6 -6 -0 -6 -7 -1 -8 -6 -0 -6 -5 -2 -2 -6 -7 -7 -2 -5 -8 -9 -9 -2 -1 -9 -6 -3 -8 -9 -2 -3 -8 -1 -6 -4 -8 -9 -9 -7 -6 -9 -5 -3 -7 -6 -5 -5 -9 -2 -6 -2 -1 -3 -7 -1 -7 -9 -9 -6 -1 -1 -1 -7 -3 -9 -7 -6 -1 -1 -1 -2 -3 -5 -5 -5 -0 -4 -1 -2 -3 -1 -1 -3 -5 -9 -6 -6 -5 -3 -1 -4 -7 -4 -7 -4 -8 -5 -2 -6 -1 -3 -9 -5 -0 -8 -4 -7 -4 -9 -4 -1 -5 -3 -9 -9 -7 -6 -9 -5 -9 -2 -3 -1 -6 -6 -7 -5 -0 -5 -1 -7 -4 -4 -1 -1 -4 -9 -5 -6 -0 -1 -3 -1 -0 -4 -8 -1 -2 -7 -9 -4 -8 -3 -7 -0 -4 -2 -4 -2 -7 -6 -3 -2 -0 -6 -5 -9 -2 -1 -8 -3 -3 -0 -6 -7 -5 -8 -7 -5 -3 -1 -7 -6 -3 -7 -9 -0 -7 -7 -1 -0 -1 -1 -7 -0 -5 -3 -8 -5 -5 -6 -5 -7 -3 -0 -2 -8 -2 -0 -3 -0 -9 -2 -1 -1 -3 -0 -5 -0 -0 -7 -5 -6 -2 -0 -3 -1 -1 -6 -5 -4 -1 -1 -4 -7 -5 -3 -6 -0 -4 -8 -2 -4 -2 -5 -1 -2 -6 -9 -1 -7 -5 -8 -0 -8 -8 -4 -5 -3 -6 -6 -6 -0 -3 -1 -1 -7 -1 -6 -2 -8 -5 -6 -4 -7 -4 -3 -3 -2 -4 -7 -0 -0 -9 -8 -5 -9 -4 -0 -8 -7 -3 -6 -7 -6 -1 -8 -6 -1 -9 -7 -7 -8 -3 -0 -9 -9 -6 -7 -7 -4 -4 -1 -8 -4 -9 -0 -0 -8 -2 -4 -3 -3 -7 -2 -3 -4 -0 -4 -2 -1 -3 -3 -6 -3 -9 -4 -3 -8 -7 -7 -6 -6 -0 -6 -9 -8 -1 -1 -3 -4 -6 -9 -9 -2 -6 -0 -1 -8 -4 -3 -9 -8 -8 -4 -0 -5 -0 -6 -0 -9 -4 -6 -0 -5 -8 -1 -5 -7 -6 -2 -3 -7 -8 -9 -3 -1 -0 -1 -0 -6 -9 -7 -0 -7 -1 -3 -2 -2 -7 -1 -6 -1 -5 -4 -4 -3 -4 -3 -9 -8 -7 -8 -6 -4 -9 -4 -4 -1 -4 -7 -1 -1 -2 -2 -0 -4 -0 -4 -0 -0 -8 -1 -8 -6 -5 -0 -1 -5 -3 -4 -6 -3 -1 -1 -6 -9 -8 -3 -5 -5 -4 -5 -8 -5 -0 -4 -0 -4 -3 -1 -6 -9 -7 -1 -1 -3 -3 -1 -9 -9 -6 -9 -1 -5 -9 -7 -3 -4 -4 -0 -9 -7 -4 -3 -0 -5 -0 -1 -9 -0 -4 -4 -2 -8 -4 -5 -9 -3 -9 -6 -1 -5 -5 -1 -9 -0 -8 -4 -6 -7 -2 -1 -5 -8 -9 -7 -7 -2 -8 -1 -3 -6 -5 -0 -9 -1 -4 -2 -3 -6 -9 -2 -3 -4 -5 -4 -2 -3 -3 -1 -1 -0 -1 -4 -9 -1 -1 -2 -7 -1 -5 -4 -9 -1 -7 -6 -0 -4 -2 -9 -9 -1 -1 -5 -3 -5 -7 -9 -7 -7 -3 -2 -7 -2 -0 -4 -7 -1 -6 -4 -6 -1 -5 -7 -3 -5 -9 -4 -7 -9 -6 -6 -3 -3 -2 -1 -4 -1 -3 -7 -7 -9 -5 -6 -0 -6 -1 -0 -9 -3 -2 -9 -2 -6 -7 -5 -2 -3 -2 -8 -3 -0 -2 -7 -9 -4 -0 -0 -5 -1 -8 -8 -5 -3 -2 -9 -6 -7 -0 -8 -0 -7 -4 -3 -8 -7 -9 -7 -7 -0 -5 -3 -2 -1 -9 -0 -6 -8 -3 -6 -2 -2 -9 -0 -9 -0 -7 -1 -3 -4 -6 -3 -9 -2 -6 -3 -7 -3 -7 -2 -3 -4 -9 -5 -9 -9 -6 -2 -6 -1 -5 -5 -1 -9 -1 -8 -9 -4 -8 -3 -5 -2 -0 -1 -6 -1 -9 -6 -2 -7 -7 -6 -6 -2 -6 -3 -5 -9 -1 -1 -3 -6 -5 -0 -0 -6 -0 -9 -4 -7 -0 -5 -9 -8 -3 -7 -6 -7 -2 -6 -1 -2 -9 -3 -0 -2 -3 -7 -7 -6 -6 -3 -1 -3 -1 -0 -1 -7 -6 -8 -3 -9 -3 -4 -2 -9 -1 -8 -2 -0 -6 -4 -6 -7 -2 -4 -1 -0 -5 -2 -6 -9 -9 -8 -5 -4 -1 -6 -3 -5 -6 -1 -2 -0 -0 -8 -0 -3 -6 -8 -7 -7 -7 -0 -0 -2 -1 -2 -8 -4 -5 -5 -3 -6 -7 -8 -4 -7 -4 -9 -1 -8 -0 -9 -1 -7 -0 -6 -4 -5 -2 -4 -5 -8 -2 -9 -1 -8 -6 -2 -7 -2 -5 -3 -8 -9 -9 -0 -7 -0 -3 -0 -9 -7 -3 -3 -8 -8 -9 -3 -2 -5 -4 -6 -8 -3 -8 -1 -7 -9 -6 -4 -0 -6 -2 -8 -4 -5 -9 -6 -7 -8 -2 -0 -0 -5 -0 -5 -9 -4 -9 -9 -5 -4 -3 -0 -5 -4 -1 -9 -1 -7 -9 -9 -5 -7 -8 -6 -4 -1 -9 -3 -1 -6 -6 -0 -1 -5 -5 -7 -6 -1 -3 -1 -9 -4 -2 -2 -6 -9 -9 -8 -1 -1 -0 -1 -6 -0 -4 -0 -2 -7 -6 -1 -4 -7 -0 -7 -1 -0 -7 -1 -1 -9 -8 -0 -6 -5 -9 -8 -6 -3 -6 -6 -6 -1 -1 -4 -0 -7 -8 -0 -4 -6 -7 -5 -5 -9 -6 -2 -4 -7 -5 -9 -3 -5 -1 -8 -0 -9 -6 -8 -1 -3 -0 -3 -1 -9 -1 -4 -5 -8 -2 -2 -9 -1 -3 -3 -0 -5 -6 -1 -8 -3 -6 -7 -2 -3 -2 -9 -7 -1 -5 -9 -8 -7 -3 -8 -4 -5 -8 -2 -1 -6 -7 -6 -1 -1 -0 -5 -0 -9 -1 -7 -4 -0 -9 -7 -5 -9 -8 -8 -7 -4 -4 -3 -7 -9 -4 -7 -2 -7 -4 -1 -5 -7 -2 -9 -5 -9 -8 -4 -5 -9 -1 -5 -1 -9 -3 -7 -6 -1 -7 -9 -2 -5 -6 -1 -8 -5 -0 -8 -8 -4 -7 -1 -9 -6 -8 -9 -4 -9 -9 -6 -5 -2 -7 -9 -8 -0 -4 -9 -0 -8 -8 -9 -0 -9 -0 -9 -7 -0 -8 -5 -5 -3 -6 -2 -5 -3 -1 -7 -3 -1 -0 -6 -5 -9 -3 -3 -9 -4 -8 -8 -7 -6 -4 -4 -0 -7 -9 -9 -6 -7 -3 -8 -9 -5 -0 -8 -6 -0 -3 -0 -1 -8 -3 -8 -6 -0 -1 -3 -0 -7 -3 -6 -9 -2 -3 -1 -7 -7 -9 -5 -9 -9 -3 -1 -5 -8 -3 -2 -5 -4 -1 -8 -4 -0 -2 -0 -1 -0 -0 -7 -1 -5 -5 -5 -9 -9 -7 -9 -4 -6 -8 -1 -9 -2 -7 -4 -8 -5 -0 -5 -9 -8 -7 -5 -0 -1 -7 -9 -6 -3 -0 -8 -7 -5 -2 -6 -1 -7 -2 -3 -8 -8 -1 -4 -6 -2 -4 -0 -2 -3 -6 -3 -8 -2 -9 -1 -8 -2 -5 -8 -7 -7 -6 -2 -0 -3 -2 -5 -1 -5 -9 -3 -3 -1 -9 -3 -2 -1 -1 -2 -6 -1 -9 -4 -4 -9 -6 -6 -7 -5 -9 -6 -6 -1 -0 -7 -8 -8 -5 -3 -7 -7 -7 -1 -4 -6 -1 -0 -0 -1 -7 -7 -2 -8 -9 -8 -2 -4 -8 -1 -3 -5 -1 -3 -3 -6 -6 -5 -8 -8 -3 -4 -5 -9 -8 -2 -0 -1 -3 -3 -5 -6 -5 -3 -6 -1 -3 -3 -7 -1 -5 -6 -6 -1 -7 -4 -1 -9 -0 -2 -8 -0 -7 -1 -3 -0 -7 -0 -7 -7 -1 -5 -8 -4 -9 -7 -0 -7 -1 -5 -3 -6 -2 -4 -7 -1 -6 -5 -9 -3 -4 -1 -9 -4 -0 -3 -5 -1 -0 -0 -5 -3 -9 -4 -9 -1 -0 -0 -5 -7 -1 -6 -8 -3 -7 -0 -3 -8 -2 -8 -6 -7 -9 -1 -8 -4 -5 -3 -1 -5 -2 -2 -5 -3 -8 -8 -2 -7 -4 -1 -5 -7 -0 -6 -6 -2 -3 -2 -2 -9 -1 -9 -6 -9 -2 -2 -6 -0 -9 -0 -0 -0 -0 -3 -0 -4 -3 -6 -7 -8 -6 -0 -5 -1 -8 -5 -6 -0 -2 -7 -1 -1 -3 -9 -9 -3 -0 -8 -5 -9 -6 -8 -3 -1 -0 -0 -9 -0 -6 -6 -2 -4 -3 -0 -2 -7 -1 -5 -8 -5 -8 -8 -4 -7 -4 -3 -6 -5 -7 -3 -1 -6 -7 -1 -3 -1 -5 -3 -1 -5 -2 -2 -6 -9 -0 -2 -1 -2 -7 -4 -4 -9 -3 -0 -9 -5 -1 -9 -6 -9 -7 -6 -5 -0 -1 -1 -3 -8 -4 -0 -0 -0 -3 -7 -9 -8 -8 -9 -9 -1 -5 -0 -9 -1 -7 -2 -0 -5 -9 -0 -6 -9 -2 -4 -2 -1 -4 -4 -4 -8 -8 -6 -5 -6 -1 -1 -5 -9 -3 -9 -7 -0 -7 -6 -5 -8 -6 -6 -0 -7 -4 -5 -1 -7 -7 -3 -5 -6 -8 -5 -3 -6 -9 -5 -6 -1 -9 -5 -0 -9 -4 -9 -1 -8 -4 -0 -9 -3 -0 -9 -4 -6 -4 -0 -1 -0 -1 -7 -5 -9 -8 -7 -8 -6 -2 -0 -0 -5 -7 -9 -6 -1 -6 -7 -2 -5 -9 -7 -1 -1 -4 -1 -6 -6 -7 -0 -2 -8 -7 -0 -9 -4 -6 -2 -6 -7 -3 -2 -9 -6 -5 -2 -5 -8 -5 -6 -9 -2 -7 -7 -9 -3 -4 -9 -2 -8 -0 -2 -4 -0 -9 -4 -5 -8 -8 -9 -3 -3 -5 -9 -0 -7 -0 -5 -5 -1 -9 -1 -9 -9 -4 -6 -4 -6 -8 -9 -0 -0 -8 -2 -1 -6 -8 -2 -0 -0 -2 -1 -5 -7 -3 -3 -5 -9 -6 -2 -3 -4 -3 -7 -4 -3 -2 -6 -6 -1 -5 -8 -0 -6 -7 -6 -2 -2 -4 -0 -6 -2 -1 -5 -2 -5 -7 -5 -6 -2 -0 -6 -8 -2 -4 -4 -5 -1 -6 -8 -1 -4 -6 -6 -1 -5 -2 -0 -0 -0 -1 -1 -4 -7 -0 -3 -6 -5 -0 -5 -3 -0 -8 -9 -1 -5 -7 -3 -3 -6 -1 -6 -1 -9 -5 -2 -0 -7 -9 -0 -2 -7 -4 -4 -6 -0 -9 -6 -8 -9 -1 -7 -4 -7 -9 -9 -7 -4 -8 -5 -9 -5 -5 -1 -9 -3 -6 -4 -0 -2 -6 -1 -8 -0 -4 -2 -1 -2 -6 -7 -3 -7 -9 -1 -5 -6 -4 -0 -1 -4 -2 -1 -1 -4 -2 -2 -1 -1 -7 -9 -4 -8 -0 -8 -9 -5 -8 -9 -4 -6 -3 -3 -3 -9 -0 -3 -6 -9 -1 -2 -6 -0 -6 -0 -5 -0 -0 -1 -8 -0 -8 -2 -0 -1 -5 -3 -9 -5 -7 -6 -8 -8 -7 -9 -0 -3 -2 -6 -0 -5 -6 -9 -6 -5 -4 -2 -1 -9 -3 -6 -6 -8 -7 -2 -2 -0 -3 -4 -5 -3 -3 -1 -5 -4 -5 -9 -7 -0 -1 -6 -5 -3 -2 -6 -4 -2 -5 -9 -3 -4 -6 -3 -5 -8 -2 -8 -9 -8 -7 -3 -3 -9 -9 -4 -6 -7 -3 -6 -9 -9 -6 -6 -0 -9 -9 -9 -9 -4 -1 -7 -2 -8 -5 -0 -5 -6 -7 -1 -8 -0 -8 -0 -3 -0 -2 -4 -9 -1 -1 -6 -7 -6 -7 -5 -3 -6 -6 -3 -9 -8 -7 -8 -8 -9 -0 -0 -7 -7 -1 -6 -0 -3 -1 -9 -8 -5 -1 -7 -0 -1 -0 -5 -9 -9 -0 -1 -9 -0 -9 -9 -4 -2 -2 -5 -5 -0 -0 -5 -9 -9 -3 -4 -2 -5 -0 -0 -3 -2 -3 -5 -9 -0 -1 -9 -5 -9 -8 -2 -0 -3 -4 -4 -1 -0 -8 -3 -5 -5 -6 -9 -1 -9 -8 -7 -0 -3 -3 -9 -1 -0 -3 -3 -9 -7 -3 -1 -9 -6 -3 -3 -4 -0 -2 -1 -3 -9 -9 -1 -7 -9 -7 -9 -6 -1 -5 -6 -6 -9 -0 -4 -2 -2 -4 -3 -7 -6 -4 -1 -4 -2 -6 -1 -0 -2 -2 -1 -0 -2 -7 -2 -6 -0 -2 -0 -2 -0 -0 -5 -0 -3 -9 -0 -6 -6 -4 -1 -5 -9 -2 -4 -6 -4 -1 -1 -3 -0 -1 -1 -5 -0 -2 -9 -7 -3 -6 -8 -7 -8 -8 -7 -2 -6 -9 -4 -5 -7 -1 -3 -6 -0 -9 -9 -4 -6 -8 -6 -4 -1 -0 -3 -3 -0 -1 -8 -9 -5 -5 -7 -7 -3 -4 -6 -2 -9 -3 -0 -7 -6 -8 -8 -2 -4 -0 -6 -9 -8 -3 -9 -2 -0 -1 -6 -7 -7 -6 -4 -6 -5 -9 -6 -1 -3 -3 -5 -2 -1 -6 -4 -1 -9 -9 -6 -6 -6 -4 -5 -9 -4 -9 -9 -2 -2 -5 -1 -6 -2 -8 -7 -2 -8 -4 -7 -6 -1 -0 -1 -9 -0 -7 -4 -9 -0 -9 -4 -9 -0 -3 -6 -7 -4 -3 -7 -0 -2 -1 -5 -1 -4 -2 -4 -5 -2 -6 -6 -8 -8 -6 -7 -9 -1 -9 -1 -3 -2 -5 -9 -0 -9 -0 -1 -6 -9 -7 -7 -3 -0 -5 -3 -1 -9 -2 -6 -7 -9 -1 -0 -5 -1 -6 -8 -8 -6 -7 -3 -7 -2 -8 -9 -1 -0 -6 -1 -1 -6 -6 -9 -0 -1 -6 -9 -8 -1 -3 -7 -7 -8 -1 -4 -7 -0 -6 -0 -6 -4 -3 -1 -9 -6 -3 -0 -0 -2 -8 -9 -8 -1 -1 -8 -1 -3 -2 -3 -1 -0 -5 -9 -5 -0 -7 -1 -0 -6 -1 -5 -1 -1 -8 -2 -2 -6 -1 -7 -9 -7 -6 -7 -5 -1 -0 -6 -2 -7 -6 -4 -4 -4 -0 -8 -2 -0 -0 -6 -4 -8 -1 -9 -2 -9 -5 -1 -5 -1 -1 -4 -7 -0 -1 -2 -4 -6 -1 -9 -2 -9 -2 -9 -2 -6 -6 -5 -5 -5 -8 -5 -6 -1 -1 -6 -1 -2 -1 -9 -4 -7 -6 -7 -1 -0 -6 -4 -6 -5 -3 -3 -8 -0 -1 -1 -6 -0 -5 -1 -2 -1 -6 -4 -3 -9 -0 -4 -0 -3 -1 -4 -9 -2 -1 -7 -0 -9 -6 -8 -5 -8 -6 -0 -6 -7 -9 -9 -3 -1 -3 -9 -3 -1 -1 -2 -0 -0 -7 -7 -5 -1 -6 -0 -6 -7 -9 -3 -6 -2 -2 -2 -9 -9 -9 -9 -2 -7 -9 -2 -8 -1 -7 -7 -3 -7 -8 -7 -2 -5 -6 -1 -9 -7 -7 -7 -8 -9 -9 -7 -8 -9 -5 -2 -9 -5 -0 -7 -6 -1 -2 -6 -2 -7 -3 -5 -6 -9 -5 -8 -8 -2 -2 -9 -7 -9 -5 -1 -1 -1 -4 -5 -6 -1 -7 -0 -7 -9 -2 -7 -2 -3 -1 -5 -7 -1 -5 -1 -6 -0 -2 -6 -9 -9 -7 -9 -8 -7 -7 -7 -5 -6 -2 -9 -8 -8 -6 -7 -3 -1 -3 -9 -1 -2 -0 -2 -6 -5 -1 -0 -9 -9 -1 -6 -8 -5 -5 -6 -2 -3 -6 -1 -6 -6 -2 -0 -6 -0 -8 -1 -2 -8 -6 -4 -8 -5 -0 -4 -5 -0 -9 -7 -9 -2 -9 -2 -8 -5 -3 -5 -9 -7 -9 -5 -7 -3 -0 -2 -8 -0 -6 -6 -6 -9 -9 -3 -9 -2 -2 -3 -3 -7 -4 -5 -8 -5 -3 -6 -0 -5 -1 -2 -6 -9 -5 -5 -2 -7 -9 -1 -9 -3 -6 -8 -8 -2 -5 -8 -3 -9 -1 -6 -9 -6 -7 -5 -8 -5 -0 -8 -6 -7 -8 -1 -7 -1 -9 -3 -8 -8 -3 -9 -9 -8 -7 -6 -0 -5 -3 -0 -9 -9 -6 -8 -7 -9 -1 -2 -3 -2 -1 -5 -2 -9 -4 -4 -9 -3 -0 -0 -1 -1 -3 -1 -1 -2 -1 -6 -2 -7 -6 -0 -4 -4 -7 -0 -7 -0 -8 -7 -1 -3 -7 -8 -9 -0 -9 -0 -0 -1 -8 -8 -7 -4 -8 -3 -5 -9 -0 -3 -6 -3 -6 -3 -0 -9 -2 -6 -9 -3 -0 -5 -4 -5 -7 -7 -4 -2 -3 -9 -2 -1 -1 -0 -1 -9 -4 -2 -2 -1 -3 -2 -7 -3 -5 -1 -3 -0 -2 -1 -1 -7 -9 -1 -8 -9 -1 -6 -9 -7 -1 -8 -9 -9 -2 -0 -6 -1 -5 -2 -0 -9 -2 -5 -5 -3 -9 -0 -1 -0 -9 -6 -0 -9 -3 -7 -8 -0 -4 -0 -2 -6 -8 -2 -1 -9 -2 -1 -8 -6 -6 -1 -4 -8 -6 -2 -1 -3 -9 -8 -3 -7 -8 -7 -8 -7 -1 -5 -6 -4 -7 -5 -5 -4 -0 -8 -1 -6 -6 -3 -3 -7 -8 -8 -4 -3 -4 -3 -2 -1 -7 -0 -9 -4 -2 -8 -6 -8 -5 -1 -8 -4 -8 -1 -4 -3 -9 -1 -2 -1 -5 -3 -6 -7 -2 -4 -7 -6 -9 -1 -9 -8 -6 -8 -2 -6 -2 -0 -1 -1 -0 -6 -3 -9 -7 -3 -1 -9 -4 -6 -9 -7 -2 -7 -8 -1 -0 -5 -1 -2 -7 -6 -6 -3 -0 -4 -1 -9 -6 -3 -9 -1 -2 -4 -1 -3 -4 -0 -1 -8 -0 -2 -9 -2 -7 -9 -9 -1 -4 -7 -3 -2 -9 -9 -1 -3 -7 -8 -4 -9 -7 -9 -7 -1 -4 -4 -0 -0 -0 -3 -5 -8 -3 -0 -4 -1 -2 -8 -1 -0 -8 -8 -3 -4 -6 -9 -3 -2 -7 -2 -6 -8 -1 -0 -1 -8 -1 -3 -7 -4 -9 -1 -3 -5 -0 -3 -5 -4 -8 -6 -1 -9 -9 -6 -6 -6 -1 -9 -0 -3 -9 -8 -4 -6 -5 -6 -8 -9 -9 -5 -1 -8 -0 -2 -0 -3 -9 -5 -7 -0 -1 -0 -7 -2 -8 -1 -8 -3 -3 -7 -9 -6 -9 -9 -5 -7 -4 -6 -4 -9 -6 -0 -0 -4 -3 -5 -7 -1 -2 -1 -9 -2 -1 -3 -1 -9 -1 -8 -5 -8 -7 -9 -3 -6 -3 -6 -1 -7 -5 -8 -2 -6 -3 -7 -0 -5 -6 -7 -9 -6 -8 -6 -0 -9 -5 -9 -6 -1 -9 -5 -6 -7 -6 -2 -6 -5 -6 -6 -0 -4 -3 -9 -4 -3 -5 -0 -2 -6 -5 -0 -7 -6 -0 -6 -0 -5 -3 -6 -1 -9 -3 -8 -4 -4 -3 -4 -5 -4 -6 -0 -6 -1 -2 -0 -3 -9 -5 -0 -4 -1 -1 -3 -3 -9 -3 -3 -6 -4 -9 -0 -6 -9 -7 -9 -8 -5 -7 -9 -1 -4 -6 -5 -1 -8 -4 -9 -7 -1 -6 -8 -6 -7 -9 -4 -4 -0 -7 -7 -9 -1 -1 -6 -8 -0 -8 -3 -2 -7 -6 -7 -0 -1 -6 -5 -4 -5 -6 -2 -5 -3 -9 -5 -1 -3 -9 -6 -9 -2 -0 -6 -2 -7 -6 -0 -0 -3 -9 -1 -2 -9 -3 -0 -6 -1 -0 -9 -9 -6 -5 -1 -3 -6 -7 -1 -5 -1 -8 -1 -7 -3 -7 -9 -5 -2 -4 -9 -6 -8 -6 -6 -0 -8 -1 -7 -7 -1 -9 -0 -1 -4 -9 -1 -7 -3 -1 -6 -2 -2 -7 -2 -4 -1 -5 -6 -1 -5 -3 -2 -6 -9 -1 -7 -4 -5 -6 -5 -6 -3 -8 -1 -3 -9 -5 -6 -7 -1 -3 -3 -7 -1 -1 -8 -0 -6 -3 -9 -3 -3 -6 -2 -2 -0 -1 -0 -1 -1 -3 -7 -2 -9 -0 -3 -8 -8 -0 -1 -9 -5 -5 -2 -1 -3 -6 -0 -2 -7 -2 -9 -1 -5 -7 -1 -7 -4 -3 -9 -4 -4 -3 -2 -0 -0 -0 -3 -1 -1 -4 -3 -9 -2 -2 -2 -8 -6 -9 -4 -0 -4 -9 -1 -0 -7 -1 -2 -1 -6 -2 -4 -0 -4 -6 -0 -1 -1 -4 -2 -6 -2 -7 -7 -3 -4 -3 -9 -0 -1 -4 -8 -6 -2 -1 -1 -7 -3 -2 -9 -2 -2 -5 -2 -1 -0 -2 -5 -0 -0 -0 -9 -2 -7 -3 -0 -2 -1 -9 -0 -8 -5 -3 -8 -2 -2 -0 -2 -7 -8 -4 -0 -3 -0 -2 -2 -8 -0 -9 -2 -3 -0 -2 -9 -9 -7 -1 -4 -2 -2 -1 -6 -7 -6 -6 -3 -3 -6 -7 -3 -9 -1 -2 -3 -5 -0 -1 -0 -9 -7 -9 -0 -1 -5 -1 -4 -3 -6 -4 -8 -1 -2 -2 -6 -4 -2 -5 -8 -2 -6 -5 -8 -3 -1 -7 -4 -6 -0 -1 -5 -8 -1 -4 -0 -3 -6 -6 -1 -6 -2 -5 -9 -1 -5 -6 -6 -1 -4 -0 -3 -6 -0 -1 -6 -8 -9 -4 -7 -7 -7 -8 -8 -7 -5 -2 -7 -8 -1 -1 -9 -5 -4 -1 -0 -1 -3 -2 -3 -6 -8 -3 -1 -2 -7 -1 -7 -7 -0 -0 -1 -0 -0 -2 -0 -0 -7 -1 -7 -8 -6 -5 -7 -1 -6 -6 -9 -9 -9 -1 -3 -9 -0 -4 -9 -2 -8 -6 -2 -7 -4 -7 -5 -0 -3 -7 -5 -6 -6 -9 -0 -3 -5 -2 -8 -9 -8 -2 -2 -9 -7 -1 -7 -7 -2 -7 -3 -2 -2 -5 -4 -0 -2 -2 -8 -1 -1 -2 -9 -2 -3 -8 -1 -6 -9 -9 -4 -3 -9 -7 -9 -0 -7 -3 -5 -2 -3 -0 -1 -9 -9 -7 -9 -2 -7 -4 -7 -0 -6 -5 -1 -9 -5 -9 -7 -2 -2 -5 -6 -3 -5 -8 -2 -3 -3 -1 -4 -7 -3 -8 -4 -5 -7 -6 -1 -9 -0 -4 -8 -0 -6 -5 -6 -5 -2 -0 -5 -3 -1 -5 -1 -4 -1 -1 -1 -1 -5 -7 -1 -0 -4 -2 -9 -5 -5 -9 -3 -5 -2 -0 -0 -1 -0 -4 -2 -4 -3 -2 -7 -9 -4 -0 -1 -9 -9 -4 -9 -3 -2 -0 -8 -4 -1 -0 -9 -3 -4 -9 -6 -9 -0 -6 -1 -1 -2 -9 -7 -8 -7 -3 -7 -0 -1 -8 -6 -2 -5 -4 -8 -9 -1 -0 -2 -8 -7 -9 -4 -4 -7 -6 -9 -4 -1 -9 -5 -8 -3 -4 -2 -6 -7 -8 -7 -8 -7 -4 -9 -4 -7 -3 -6 -9 -1 -1 -1 -0 -1 -8 -1 -6 -9 -3 -3 -6 -9 -5 -8 -1 -9 -2 -3 -7 -9 -9 -2 -9 -8 -3 -4 -5 -1 -9 -9 -6 -1 -3 -5 -2 -9 -6 -5 -3 -5 -1 -5 -0 -2 -6 -8 -9 -9 -0 -6 -6 -7 -5 -8 -2 -0 -9 -5 -0 -1 -9 -7 -2 -3 -3 -0 -4 -9 -3 -1 -3 -9 -0 -3 -5 -4 -9 -4 -6 -8 -9 -6 -9 -3 -8 -6 -5 -0 -4 -8 -6 -0 -0 -9 -1 -4 -2 -5 -6 -3 -8 -0 -8 -8 -2 -4 -2 -7 -6 -9 -7 -8 -6 -9 -8 -6 -1 -5 -4 -3 -9 -9 -5 -0 -8 -2 -9 -1 -6 -9 -1 -0 -1 -8 -7 -6 -1 -6 -4 -1 -7 -5 -9 -1 -1 -2 -3 -9 -0 -7 -2 -2 -4 -1 -7 -7 -7 -8 -3 -5 -5 -6 -2 -1 -0 -8 -7 -7 -5 -1 -1 -8 -6 -5 -6 -6 -9 -8 -1 -7 -4 -9 -1 -6 -7 -3 -0 -7 -2 -1 -6 -8 -1 -3 -9 -0 -7 -5 -3 -2 -9 -0 -6 -1 -4 -0 -9 -7 -0 -6 -5 -5 -7 -0 -1 -5 -6 -1 -4 -8 -6 -8 -9 -5 -1 -0 -2 -2 -0 -7 -8 -2 -5 -1 -8 -3 -7 -6 -9 -1 -4 -9 -1 -0 -3 -3 -5 -9 -2 -7 -6 -3 -3 -8 -0 -0 -9 -7 -5 -5 -0 -3 -8 -7 -3 -1 -0 -7 -1 -5 -7 -0 -2 -5 -9 -2 -6 -1 -3 -1 -1 -3 -6 -6 -8 -4 -2 -3 -0 -1 -4 -4 -1 -1 -8 -4 -7 -6 -7 -5 -1 -9 -2 -0 -9 -1 -4 -3 -9 -4 -6 -9 -8 -5 -6 -8 -9 -7 -0 -0 -1 -0 -9 -7 -0 -2 -2 -7 -9 -6 -9 -5 -6 -1 -1 -1 -5 -8 -7 -9 -6 -2 -2 -2 -8 -5 -7 -1 -1 -1 -2 -9 -1 -8 -1 -3 -2 -1 -0 -6 -4 -7 -6 -5 -0 -1 -2 -8 -8 -4 -4 -3 -7 -4 -4 -9 -2 -8 -8 -6 -1 -5 -4 -5 -6 -8 -7 -0 -0 -1 -5 -4 -1 -5 -7 -3 -2 -0 -9 -9 -4 -9 -5 -0 -3 -6 -2 -3 -1 -7 -6 -0 -8 -2 -7 -7 -5 -8 -7 -4 -5 -0 -1 -9 -7 -4 -5 -0 -9 -8 -6 -3 -3 -1 -6 -1 -8 -0 -9 -9 -1 -1 -3 -7 -0 -0 -3 -0 -4 -9 -9 -8 -8 -0 -9 -0 -1 -6 -6 -6 -0 -2 -5 -7 -0 -6 -9 -7 -2 -2 -5 -3 -6 -6 -9 -2 -5 -4 -3 -5 -2 -4 -5 -4 -1 -7 -2 -3 -1 -9 -9 -2 -9 -0 -8 -1 -5 -7 -8 -6 -6 -8 -3 -2 -6 -7 -0 -6 -0 -2 -2 -3 -0 -6 -3 -3 -4 -2 -1 -4 -3 -3 -0 -0 -3 -2 -4 -1 -5 -9 -2 -4 -2 -5 -8 -7 -9 -9 -1 -5 -0 -0 -9 -0 -8 -8 -0 -9 -8 -6 -2 -3 -2 -0 -6 -3 -3 -1 -9 -2 -0 -5 -2 -8 -9 -4 -2 -6 -0 -2 -0 -6 -5 -3 -4 -1 -2 -2 -4 -9 -4 -3 -2 -1 -9 -1 -6 -1 -2 -3 -4 -0 -1 -9 -4 -0 -0 -4 -8 -1 -9 -2 -5 -3 -4 -3 -7 -0 -7 -9 -7 -9 -5 -9 -7 -7 -0 -4 -2 -1 -1 -8 -5 -0 -4 -9 -8 -8 -2 -4 -1 -4 -1 -4 -1 -0 -9 -9 -5 -6 -9 -9 -1 -2 -6 -0 -3 -0 -3 -3 -0 -4 -0 -1 -0 -8 -4 -9 -3 -7 -1 -4 -1 -7 -6 -0 -7 -7 -1 -5 -0 -3 -6 -0 -2 -8 -5 -3 -5 -7 -7 -2 -9 -6 -7 -8 -1 -5 -7 -3 -1 -7 -3 -1 -8 -0 -1 -0 -4 -3 -2 -7 -9 -7 -9 -3 -6 -2 -3 -4 -1 -3 -0 -9 -9 -2 -6 -4 -0 -0 -7 -5 -1 -8 -3 -8 -1 -6 -5 -8 -9 -2 -2 -0 -7 -1 -6 -2 -1 -6 -8 -4 -3 -5 -9 -1 -0 -5 -3 -1 -9 -2 -1 -8 -1 -3 -6 -0 -1 -2 -4 -1 -3 -7 -4 -9 -4 -2 -0 -6 -3 -5 -0 -4 -3 -6 -1 -7 -6 -2 -7 -1 -7 -0 -6 -9 -6 -5 -1 -3 -6 -8 -1 -9 -0 -6 -6 -9 -3 -6 -8 -2 -9 -0 -6 -1 -8 -1 -1 -0 -0 -9 -9 -9 -4 -8 -4 -1 -6 -4 -9 -1 -8 -9 -2 -3 -4 -6 -1 -0 -1 -6 -7 -9 -0 -0 -8 -5 -4 -2 -5 -2 -8 -4 -6 -9 -7 -1 -4 -3 -5 -2 -9 -3 -3 -5 -3 -0 -0 -1 -9 -2 -5 -3 -7 -6 -5 -9 -6 -5 -0 -9 -1 -3 -8 -5 -7 -7 -0 -7 -7 -1 -5 -6 -7 -0 -4 -3 -0 -0 -0 -0 -7 -6 -8 -2 -6 -7 -1 -7 -1 -0 -2 -3 -5 -1 -8 -5 -4 -7 -6 -2 -6 -6 -8 -3 -8 -5 -1 -5 -2 -6 -5 -1 -5 -8 -3 -5 -5 -3 -2 -3 -5 -5 -8 -6 -7 -0 -3 -8 -8 -4 -2 -6 -4 -5 -8 -3 -0 -9 -1 -1 -3 -0 -9 -6 -7 -8 -2 -5 -3 -6 -2 -0 -2 -5 -1 -2 -9 -9 -0 -2 -5 -5 -6 -1 -4 -1 -3 -1 -5 -5 -0 -1 -9 -3 -9 -5 -0 -7 -9 -8 -3 -0 -1 -3 -3 -8 -1 -3 -5 -7 -0 -1 -6 -4 -8 -5 -0 -6 -0 -4 -5 -8 -2 -1 -5 -4 -0 -1 -4 -1 -7 -3 -9 -2 -9 -1 -2 -1 -7 -6 -6 -1 -5 -9 -8 -9 -0 -2 -3 -1 -7 -3 -1 -5 -2 -7 -3 -2 -6 -9 -7 -4 -0 -5 -1 -5 -9 -1 -0 -9 -4 -5 -9 -8 -7 -1 -3 -3 -2 -4 -1 -1 -8 -0 -5 -2 -8 -9 -0 -9 -7 -0 -9 -9 -2 -7 -6 -1 -7 -1 -6 -0 -2 -9 -9 -9 -7 -8 -2 -4 -0 -9 -3 -5 -9 -4 -2 -0 -3 -2 -0 -2 -9 -4 -8 -5 -5 -6 -9 -6 -8 -4 -7 -6 -7 -4 -9 -4 -2 -1 -0 -8 -1 -7 -6 -0 -1 -9 -3 -6 -5 -5 -0 -7 -1 -3 -6 -9 -3 -3 -4 -8 -4 -7 -9 -1 -2 -9 -6 -7 -4 -8 -9 -3 -9 -5 -6 -7 -9 -2 -2 -1 -8 -3 -2 -7 -1 -7 -1 -2 -8 -7 -9 -8 -0 -9 -4 -0 -0 -2 -2 -4 -2 -0 -7 -6 -3 -2 -7 -4 -1 -2 -7 -4 -9 -2 -1 -7 -5 -8 -0 -5 -7 -9 -7 -1 -5 -5 -4 -2 -4 -7 -9 -9 -6 -4 -5 -4 -9 -1 -9 -6 -5 -6 -2 -8 -6 -8 -3 -8 -9 -6 -8 -8 -6 -4 -0 -2 -6 -1 -3 -8 -9 -8 -7 -7 -7 -8 -0 -7 -9 -5 -0 -3 -7 -4 -6 -4 -7 -2 -9 -6 -4 -0 -4 -6 -1 -8 -4 -9 -9 -4 -3 -6 -9 -0 -4 -1 -8 -5 -7 -8 -5 -2 -8 -8 -7 -0 -5 -0 -7 -2 -3 -4 -7 -8 -1 -5 -5 -9 -5 -2 -5 -0 -5 -6 -9 -7 -4 -1 -1 -9 -1 -9 -9 -4 -8 -4 -3 -7 -6 -2 -0 -1 -8 -9 -6 -7 -9 -5 -7 -5 -3 -1 -6 -0 -3 -2 -4 -5 -1 -5 -1 -5 -3 -5 -8 -5 -8 -5 -2 -7 -0 -1 -1 -1 -9 -0 -9 -9 -2 -0 -7 -5 -1 -3 -4 -7 -8 -0 -1 -2 -9 -3 -1 -6 -2 -0 -5 -0 -1 -6 -1 -9 -7 -7 -8 -6 -8 -4 -0 -7 -1 -0 -1 -3 -4 -9 -0 -9 -4 -5 -1 -6 -9 -4 -6 -6 -6 -1 -1 -3 -5 -8 -7 -4 -8 -6 -9 -8 -1 -1 -1 -3 -3 -5 -6 -5 -6 -2 -8 -7 -9 -1 -1 -9 -9 -0 -6 -6 -2 -3 -8 -3 -0 -0 -5 -0 -9 -2 -1 -3 -3 -5 -1 -8 -9 -9 -1 -5 -6 -9 -1 -7 -2 -9 -1 -6 -3 -5 -0 -7 -7 -6 -5 -1 -8 -1 -3 -4 -5 -0 -7 -4 -2 -8 -0 -4 -5 -1 -9 -7 -4 -2 -8 -8 -5 -8 -6 -8 -7 -9 -9 -7 -9 -4 -2 -6 -9 -1 -9 -9 -0 -6 -8 -3 -0 -1 -4 -6 -6 -8 -1 -9 -4 -3 -7 -2 -8 -5 -1 -9 -6 -8 -0 -0 -1 -7 -9 -4 -9 -6 -0 -7 -3 -9 -7 -2 -7 -4 -2 -0 -5 -2 -6 -4 -1 -7 -3 -0 -4 -3 -1 -6 -1 -4 -9 -2 -1 -0 -3 -3 -9 -0 -9 -6 -6 -0 -2 -7 -3 -0 -5 -8 -8 -5 -3 -5 -0 -8 -0 -7 -3 -3 -2 -5 -1 -3 -6 -5 -9 -7 -2 -2 -9 -0 -8 -8 -0 -5 -0 -8 -0 -4 -1 -6 -7 -7 -8 -1 -0 -2 -6 -4 -6 -8 -8 -6 -6 -4 -9 -4 -5 -5 -6 -3 -1 -7 -6 -1 -9 -9 -0 -6 -6 -5 -2 -0 -8 -9 -3 -1 -8 -1 -0 -3 -0 -6 -6 -8 -6 -2 -3 -2 -9 -2 -0 -6 -0 -2 -1 -2 -6 -6 -1 -7 -7 -0 -2 -9 -4 -1 -0 -0 -7 -5 -8 -5 -6 -1 -7 -0 -6 -6 -5 -9 -3 -6 -4 -2 -1 -1 -7 -1 -5 -9 -3 -3 -7 -6 -1 -6 -2 -1 -2 -5 -7 -0 -5 -2 -6 -0 -9 -1 -0 -5 -5 -2 -4 -6 -3 -0 -9 -4 -9 -4 -7 -0 -0 -4 -0 -9 -2 -7 -1 -1 -2 -1 -1 -6 -3 -2 -5 -5 -1 -8 -2 -0 -3 -8 -4 -1 -6 -8 -5 -8 -5 -3 -5 -8 -6 -7 -1 -6 -1 -9 -3 -9 -3 -9 -3 -1 -9 -8 -8 -3 -1 -7 -8 -6 -5 -4 -6 -0 -0 -2 -0 -0 -0 -2 -6 -7 -5 -1 -0 -0 -0 -9 -3 -8 -0 -9 -5 -9 -4 -2 -3 -2 -7 -2 -0 -2 -6 -2 -2 -8 -8 -8 -5 -1 -2 -2 -6 -7 -0 -2 -2 -1 -4 -3 -4 -1 -9 -7 -0 -5 -6 -5 -1 -8 -5 -3 -3 -9 -0 -6 -6 -9 -2 -1 -0 -4 -8 -4 -5 -7 -9 -2 -2 -2 -1 -1 -4 -4 -7 -8 -6 -8 -6 -5 -5 -8 -1 -8 -2 -9 -1 -9 -7 -2 -4 -4 -4 -9 -9 -3 -0 -5 -5 -5 -5 -2 -7 -0 -0 -1 -3 -5 -3 -0 -0 -0 -3 -1 -4 -0 -2 -6 -9 -7 -6 -9 -6 -6 -9 -0 -2 -2 -4 -1 -9 -2 -7 -2 -5 -9 -4 -6 -2 -7 -6 -8 -9 -1 -8 -8 -0 -2 -4 -9 -9 -1 -7 -1 -9 -9 -2 -1 -4 -5 -2 -7 -6 -0 -0 -3 -0 -6 -6 -8 -0 -0 -3 -6 -7 -8 -0 -8 -6 -4 -5 -8 -1 -5 -0 -6 -6 -9 -5 -1 -6 -4 -3 -0 -7 -2 -5 -5 -9 -9 -5 -6 -9 -0 -1 -9 -2 -9 -5 -6 -4 -9 -7 -6 -2 -8 -0 -4 -1 -8 -2 -1 -3 -4 -1 -7 -7 -2 -9 -3 -8 -6 -3 -2 -2 -6 -3 -5 -7 -1 -1 -1 -7 -7 -5 -2 -9 -7 -9 -1 -5 -6 -4 -4 -4 -1 -9 -0 -5 -4 -3 -4 -6 -6 -3 -8 -6 -7 -4 -9 -5 -9 -0 -0 -0 -8 -6 -4 -2 -3 -0 -9 -8 -5 -9 -8 -6 -7 -6 -1 -4 -0 -1 -6 -1 -4 -5 -6 -1 -1 -9 -1 -5 -7 -5 -9 -2 -5 -1 -0 -6 -7 -1 -1 -6 -4 -0 -5 -6 -0 -8 -0 -7 -4 -9 -9 -0 -2 -2 -0 -3 -0 -5 -1 -0 -1 -1 -2 -8 -2 -6 -2 -6 -2 -0 -2 -9 -7 -3 -3 -8 -5 -0 -6 -6 -9 -5 -3 -2 -7 -3 -4 -7 -7 -5 -8 -1 -1 -6 -0 -5 -7 -5 -9 -5 -0 -4 -3 -7 -6 -3 -5 -4 -5 -1 -1 -9 -4 -8 -3 -7 -3 -0 -9 -4 -7 -8 -4 -8 -1 -1 -0 -5 -6 -7 -9 -5 -6 -1 -0 -6 -0 -2 -1 -7 -9 -0 -3 -2 -8 -7 -0 -1 -3 -4 -9 -0 -7 -6 -1 -3 -9 -2 -3 -1 -4 -1 -1 -7 -4 -4 -5 -1 -2 -8 -9 -6 -6 -5 -4 -0 -6 -1 -3 -5 -2 -8 -1 -9 -0 -5 -3 -3 -9 -2 -9 -1 -7 -4 -5 -0 -5 -1 -9 -1 -1 -9 -9 -9 -6 -6 -1 -4 -5 -4 -8 -7 -6 -1 -1 -0 -4 -6 -2 -9 -9 -5 -3 -6 -4 -3 -3 -8 -2 -2 -1 -5 -8 -7 -5 -2 -8 -0 -7 -2 -5 -5 -6 -4 -8 -7 -3 -8 -2 -1 -3 -9 -5 -0 -4 -0 -6 -5 -5 -0 -0 -6 -7 -7 -1 -1 -1 -5 -6 -6 -5 -1 -4 -9 -5 -0 -4 -9 -1 -7 -7 -4 -6 -9 -3 -0 -0 -7 -8 -0 -8 -3 -0 -5 -8 -5 -1 -6 -0 -9 -0 -9 -5 -3 -0 -1 -7 -1 -1 -4 -4 -0 -4 -1 -7 -1 -5 -5 -4 -5 -6 -8 -3 -3 -1 -1 -8 -0 -9 -8 -2 -7 -2 -9 -8 -9 -5 -4 -8 -2 -2 -3 -2 -6 -8 -9 -1 -1 -9 -5 -9 -1 -7 -2 -7 -9 -1 -2 -9 -7 -5 -5 -5 -7 -4 -3 -5 -9 -7 -8 -0 -6 -1 -4 -8 -2 -3 -1 -8 -2 -9 -7 -9 -7 -3 -3 -2 -9 -2 -7 -6 -1 -9 -9 -2 -1 -2 -5 -8 -1 -6 -3 -0 -9 -1 -2 -6 -5 -5 -8 -4 -2 -6 -1 -6 -1 -0 -4 -9 -0 -1 -4 -1 -2 -1 -6 -0 -7 -6 -1 -0 -0 -1 -8 -3 -0 -6 -7 -0 -3 -2 -0 -1 -7 -8 -4 -4 -6 -1 -6 -2 -0 -0 -3 -9 -9 -8 -7 -5 -8 -0 -1 -0 -0 -0 -5 -6 -2 -2 -5 -3 -8 -8 -1 -9 -2 -7 -4 -0 -5 -3 -8 -3 -6 -9 -9 -3 -4 -8 -9 -4 -3 -2 -9 -2 -3 -7 -3 -7 -7 -7 -0 -9 -9 -4 -2 -3 -6 -6 -7 -9 -3 -9 -7 -1 -4 -9 -0 -9 -9 -8 -0 -0 -9 -9 -7 -3 -9 -4 -4 -9 -2 -1 -9 -9 -6 -9 -1 -9 -6 -4 -7 -7 -7 -2 -7 -6 -2 -9 -6 -6 -7 -3 -9 -8 -1 -0 -9 -2 -8 -0 -3 -1 -4 -5 -2 -1 -9 -4 -4 -1 -0 -9 -1 -9 -7 -4 -5 -9 -3 -8 -5 -7 -0 -1 -4 -1 -8 -1 -6 -6 -9 -6 -8 -8 -1 -6 -2 -7 -8 -0 -2 -0 -4 -5 -5 -8 -1 -7 -6 -5 -4 -6 -0 -2 -2 -1 -5 -7 -2 -4 -6 -4 -4 -9 -2 -2 -7 -6 -1 -7 -1 -6 -3 -9 -7 -5 -1 -7 -9 -2 -2 -5 -7 -3 -5 -7 -6 -2 -8 -7 -2 -8 -9 -9 -2 -9 -2 -4 -4 -1 -6 -0 -6 -9 -6 -5 -6 -9 -6 -1 -2 -2 -5 -0 -9 -4 -1 -9 -4 -3 -6 -9 -6 -5 -7 -0 -3 -0 -0 -2 -7 -0 -7 -8 -7 -2 -7 -5 -8 -0 -7 -2 -9 -6 -2 -0 -9 -7 -3 -5 -0 -5 -9 -0 -9 -6 -9 -1 -9 -1 -0 -0 -8 -8 -9 -8 -3 -9 -7 -7 -8 -2 -5 -4 -7 -5 -5 -7 -1 -1 -9 -2 -7 -9 -5 -7 -6 -1 -2 -2 -9 -1 -4 -6 -5 -4 -4 -8 -4 -7 -1 -2 -0 -7 -6 -7 -6 -7 -1 -5 -2 -9 -2 -7 -6 -6 -6 -1 -1 -4 -6 -9 -4 -2 -1 -0 -5 -1 -5 -7 -4 -6 -2 -3 -5 -2 -5 -9 -1 -7 -3 -8 -0 -1 -6 -5 -9 -7 -7 -0 -9 -6 -3 -8 -9 -0 -1 -2 -1 -1 -3 -5 -9 -9 -8 -7 -1 -9 -9 -3 -5 -7 -1 -4 -4 -7 -4 -3 -9 -1 -9 -1 -3 -7 -3 -1 -4 -7 -3 -5 -6 -5 -6 -1 -8 -9 -4 -7 -1 -1 -8 -2 -6 -4 -6 -6 -0 -6 -2 -3 -3 -4 -3 -5 -6 -8 -2 -4 -3 -8 -0 -1 -0 -9 -3 -4 -2 -3 -0 -2 -5 -8 -1 -7 -5 -0 -9 -7 -7 -7 -1 -0 -4 -9 -4 -1 -6 -7 -4 -4 -6 -0 -7 -2 -2 -3 -9 -1 -1 -2 -2 -2 -3 -8 -0 -5 -2 -6 -2 -1 -1 -8 -7 -8 -2 -3 -8 -7 -1 -6 -3 -7 -0 -5 -6 -6 -7 -4 -2 -2 -1 -7 -3 -4 -3 -9 -8 -8 -0 -2 -3 -9 -1 -3 -6 -3 -8 -7 -9 -2 -6 -3 -6 -9 -2 -2 -5 -9 -3 -7 -2 -3 -6 -9 -1 -9 -6 -4 -5 -6 -5 -0 -7 -3 -9 -9 -1 -6 -9 -1 -6 -9 -3 -5 -2 -2 -7 -9 -7 -2 -9 -0 -9 -8 -2 -1 -9 -1 -2 -5 -0 -9 -0 -5 -3 -8 -9 -5 -8 -6 -1 -9 -4 -1 -6 -6 -9 -6 -2 -7 -3 -8 -2 -4 -9 -1 -6 -4 -1 -1 -2 -3 -7 -5 -5 -2 -5 -3 -2 -1 -5 -8 -0 -4 -9 -2 -4 -6 -2 -8 -9 -9 -5 -8 -0 -5 -0 -0 -6 -6 -2 -6 -2 -0 -7 -1 -2 -8 -2 -9 -1 -6 -4 -3 -0 -0 -1 -5 -9 -3 -1 -0 -2 -5 -6 -8 -4 -4 -3 -4 -9 -7 -6 -6 -8 -4 -8 -3 -3 -8 -4 -1 -8 -2 -5 -5 -2 -9 -0 -0 -4 -1 -5 -7 -7 -3 -3 -6 -2 -6 -5 -1 -7 -3 -1 -7 -7 -9 -8 -7 -3 -3 -3 -1 -6 -1 -9 -5 -9 -3 -0 -0 -2 -0 -8 -0 -0 -2 -5 -5 -8 -5 -9 -7 -8 -9 -1 -5 -9 -7 -9 -7 -3 -1 -4 -3 -8 -4 -0 -7 -0 -6 -0 -9 -8 -1 -5 -3 -5 -6 -8 -7 -9 -1 -4 -4 -0 -2 -0 -4 -5 -5 -8 -8 -8 -9 -6 -6 -5 -1 -5 -7 -7 -5 -2 -2 -2 -3 -8 -6 -4 -8 -4 -1 -2 -7 -5 -5 -0 -4 -6 -6 -1 -4 -4 -6 -5 -5 -5 -9 -4 -6 -1 -3 -0 -2 -9 -5 -2 -3 -3 -2 -8 -1 -5 -6 -3 -4 -6 -4 -6 -3 -0 -0 -5 -5 -0 -7 -9 -1 -3 -1 -4 -8 -7 -5 -8 -0 -0 -0 -0 -6 -9 -7 -9 -9 -9 -0 -2 -4 -0 -7 -6 -1 -1 -4 -5 -3 -0 -8 -7 -8 -1 -3 -4 -1 -5 -2 -3 -0 -7 -1 -0 -3 -8 -5 -0 -3 -1 -5 -4 -5 -3 -6 -1 -6 -6 -1 -4 -7 -3 -7 -8 -6 -0 -5 -6 -6 -9 -5 -5 -2 -2 -6 -1 -5 -6 -0 -3 -2 -6 -6 -1 -5 -9 -5 -4 -6 -1 -1 -7 -2 -0 -5 -8 -1 -0 -4 -8 -6 -1 -9 -5 -1 -9 -6 -6 -7 -6 -7 -3 -1 -1 -1 -6 -4 -8 -1 -4 -4 -1 -4 -1 -1 -7 -9 -6 -3 -8 -6 -6 -6 -2 -5 -9 -4 -5 -1 -6 -6 -3 -0 -7 -9 -9 -6 -1 -1 -5 -1 -8 -1 -6 -9 -2 -7 -7 -0 -1 -9 -3 -9 -3 -2 -4 -9 -8 -7 -7 -1 -1 -6 -9 -5 -3 -5 -2 -8 -8 -9 -2 -8 -3 -9 -0 -8 -6 -6 -5 -0 -6 -7 -8 -9 -7 -4 -2 -7 -2 -8 -0 -0 -4 -2 -9 -0 -1 -9 -9 -9 -1 -7 -0 -7 -0 -3 -1 -6 -8 -1 -9 -4 -0 -7 -0 -9 -8 -1 -8 -8 -1 -2 -6 -5 -1 -0 -2 -6 -0 -3 -7 -0 -5 -3 -7 -7 -0 -5 -5 -2 -5 -1 -2 -7 -2 -7 -5 -6 -7 -6 -2 -4 -0 -1 -8 -6 -6 -9 -4 -6 -6 -2 -4 -4 -0 -1 -7 -9 -1 -8 -3 -3 -1 -4 -5 -2 -2 -7 -4 -1 -7 -4 -8 -9 -6 -8 -7 -8 -7 -0 -9 -4 -0 -2 -5 -0 -3 -6 -9 -4 -1 -0 -1 -2 -8 -1 -6 -0 -1 -2 -6 -3 -3 -2 -0 -6 -9 -2 -1 -3 -2 -8 -8 -0 -6 -1 -1 -8 -7 -4 -8 -3 -1 -9 -5 -5 -1 -8 -5 -0 -5 -9 -9 -5 -4 -5 -7 -3 -5 -7 -8 -0 -2 -1 -4 -0 -9 -1 -7 -9 -1 -6 -7 -1 -3 -5 -4 -4 -4 -0 -3 -5 -1 -4 -2 -1 -4 -0 -1 -1 -7 -5 -7 -1 -3 -3 -0 -4 -9 -4 -6 -8 -2 -9 -5 -1 -9 -5 -0 -8 -2 -5 -4 -3 -6 -7 -2 -5 -3 -6 -0 -1 -4 -9 -3 -6 -6 -5 -1 -9 -3 -0 -3 -8 -9 -7 -1 -3 -0 -5 -7 -9 -0 -4 -5 -9 -8 -2 -8 -3 -1 -5 -8 -3 -7 -5 -0 -3 -5 -4 -4 -2 -5 -9 -6 -6 -0 -1 -4 -1 -2 -6 -5 -0 -3 -8 -3 -0 -1 -1 -2 -9 -6 -1 -1 -0 -7 -2 -8 -4 -7 -2 -1 -6 -1 -8 -6 -7 -7 -6 -3 -2 -4 -1 -4 -5 -8 -3 -5 -4 -8 -4 -6 -6 -1 -7 -5 -6 -1 -3 -2 -2 -7 -0 -0 -2 -9 -1 -3 -3 -3 -3 -9 -3 -4 -1 -2 -6 -8 -1 -9 -5 -4 -7 -9 -0 -7 -2 -9 -9 -1 -4 -0 -6 -7 -8 -7 -4 -7 -1 -9 -4 -9 -6 -5 -1 -9 -3 -6 -6 -5 -2 -8 -3 -8 -2 -4 -0 -6 -0 -1 -5 -9 -0 -1 -6 -5 -2 -3 -0 -3 -0 -0 -8 -4 -5 -0 -5 -3 -0 -2 -3 -1 -2 -4 -3 -0 -2 -0 -7 -9 -3 -3 -9 -6 -5 -9 -8 -1 -8 -0 -6 -5 -1 -9 -5 -1 -7 -1 -9 -6 -2 -1 -1 -0 -5 -6 -4 -1 -9 -5 -3 -4 -5 -3 -8 -5 -3 -7 -2 -2 -2 -9 -8 -3 -0 -6 -7 -6 -2 -8 -6 -2 -1 -5 -7 -2 -1 -2 -3 -9 -4 -1 -9 -2 -8 -4 -6 -7 -8 -4 -9 -9 -4 -5 -1 -2 -0 -2 -9 -6 -1 -5 -0 -9 -5 -4 -7 -5 -8 -1 -5 -1 -1 -0 -5 -4 -2 -0 -0 -9 -0 -2 -7 -7 -5 -2 -5 -7 -6 -3 -7 -5 -4 -0 -8 -6 -3 -7 -3 -1 -6 -2 -4 -4 -4 -0 -5 -1 -8 -8 -3 -4 -5 -0 -2 -2 -0 -1 -1 -6 -1 -4 -3 -1 -5 -9 -9 -2 -5 -0 -0 -2 -4 -2 -8 -2 -8 -4 -9 -4 -4 -8 -0 -5 -8 -5 -9 -9 -4 -4 -9 -2 -4 -8 -3 -0 -9 -8 -7 -6 -2 -4 -2 -6 -2 -2 -7 -1 -1 -0 -2 -9 -9 -0 -5 -4 -7 -0 -5 -9 -4 -1 -5 -6 -6 -8 -1 -2 -4 -3 -3 -2 -9 -7 -1 -4 -9 -6 -9 -0 -2 -4 -4 -5 -7 -8 -9 -4 -2 -4 -1 -7 -8 -2 -8 -0 -1 -2 -9 -9 -7 -0 -1 -2 -6 -9 -4 -2 -1 -4 -5 -0 -8 -6 -1 -9 -5 -1 -6 -2 -1 -8 -0 -5 -1 -9 -9 -6 -6 -8 -1 -1 -7 -9 -4 -7 -7 -3 -4 -6 -0 -6 -3 -0 -6 -3 -0 -1 -3 -2 -6 -3 -2 -0 -5 -9 -1 -3 -9 -0 -2 -0 -5 -8 -9 -6 -6 -5 -2 -9 -7 -6 -0 -7 -9 -1 -3 -9 -1 -7 -6 -4 -9 -7 -6 -0 -0 -4 -8 -4 -9 -8 -3 -5 -1 -7 -7 -1 -4 -1 -6 -3 -9 -7 -6 -6 -1 -9 -4 -0 -0 -4 -4 -8 -3 -1 -7 -5 -8 -3 -7 -4 -1 -0 -3 -2 -9 -3 -2 -2 -6 -0 -9 -9 -8 -3 -1 -8 -6 -4 -2 -2 -1 -7 -3 -1 -9 -5 -0 -6 -8 -1 -7 -8 -3 -7 -6 -7 -7 -3 -9 -2 -4 -5 -7 -7 -9 -0 -9 -1 -8 -1 -8 -9 -4 -1 -9 -9 -6 -1 -7 -5 -3 -5 -3 -1 -8 -0 -0 -1 -0 -3 -6 -6 -1 -9 -9 -0 -1 -0 -2 -0 -6 -7 -7 -5 -3 -1 -8 -9 -7 -2 -4 -6 -2 -5 -0 -6 -5 -6 -8 -3 -4 -1 -1 -4 -6 -8 -7 -1 -8 -6 -8 -1 -2 -3 -3 -2 -3 -3 -6 -8 -2 -7 -6 -9 -8 -0 -9 -7 -7 -7 -8 -3 -1 -2 -3 -1 -4 -3 -6 -4 -8 -3 -1 -3 -6 -9 -6 -9 -0 -3 -9 -0 -7 -7 -3 -0 -0 -9 -3 -5 -7 -9 -8 -6 -0 -7 -7 -2 -8 -7 -9 -1 -2 -5 -6 -0 -7 -8 -1 -0 -3 -6 -9 -9 -5 -0 -3 -0 -1 -1 -6 -2 -5 -9 -5 -4 -0 -5 -5 -1 -2 -7 -6 -5 -3 -0 -5 -6 -9 -0 -7 -8 -1 -7 -1 -8 -7 -2 -7 -9 -7 -3 -2 -1 -2 -8 -4 -9 -2 -1 -3 -1 -8 -1 -6 -2 -7 -3 -9 -9 -4 -1 -6 -3 -1 -1 -7 -5 -3 -5 -2 -2 -9 -7 -1 -3 -9 -1 -1 -1 -8 -1 -6 -2 -6 -6 -1 -8 -2 -9 -7 -0 -3 -5 -7 -8 -7 -8 -7 -9 -3 -7 -1 -8 -5 -4 -7 -5 -3 -0 -5 -9 -7 -0 -7 -7 -4 -4 -5 -8 -9 -2 -9 -7 -5 -1 -4 -9 -9 -6 -4 -2 -0 -2 -6 -2 -2 -8 -4 -1 -6 -1 -2 -2 -1 -3 -1 -2 -4 -6 -4 -3 -5 -5 -5 -1 -0 -1 -1 -9 -1 -7 -2 -6 -9 -6 -5 -2 -5 -4 -8 -9 -3 -4 -8 -9 -7 -3 -5 -6 -5 -9 -8 -5 -7 -0 -4 -5 -1 -0 -1 -6 -9 -2 -1 -9 -7 -0 -9 -3 -1 -6 -3 -6 -0 -5 -2 -6 -5 -7 -9 -0 -2 -0 -8 -4 -0 -9 -9 -6 -0 -7 -5 -0 -1 -9 -6 -1 -1 -2 -7 -0 -3 -3 -8 -9 -9 -8 -4 -5 -4 -7 -9 -8 -6 -9 -8 -3 -0 -9 -6 -7 -9 -3 -5 -8 -1 -2 -7 -8 -7 -1 -6 -8 -3 -1 -6 -8 -7 -6 -9 -1 -5 -9 -0 -9 -4 -3 -3 -3 -4 -1 -9 -3 -0 -5 -2 -0 -6 -1 -6 -7 -9 -0 -4 -5 -4 -3 -5 -9 -4 -8 -7 -2 -8 -2 -6 -7 -9 -7 -6 -4 -6 -3 -4 -5 -7 -4 -2 -2 -9 -6 -9 -0 -5 -0 -0 -3 -3 -5 -3 -7 -6 -2 -2 -4 -9 -0 -5 -3 -1 -8 -5 -9 -9 -7 -1 -4 -3 -6 -7 -8 -1 -6 -4 -1 -4 -9 -7 -1 -3 -0 -8 -7 -8 -7 -1 -6 -9 -9 -8 -3 -1 -6 -8 -5 -0 -8 -4 -1 -6 -8 -1 -9 -4 -3 -8 -4 -0 -9 -9 -4 -9 -3 -7 -2 -8 -0 -4 -3 -7 -4 -4 -6 -5 -3 -0 -5 -3 -1 -4 -6 -5 -5 -9 -3 -1 -1 -3 -5 -0 -9 -2 -3 -5 -9 -2 -4 -3 -1 -0 -7 -7 -5 -6 -0 -4 -8 -8 -2 -0 -3 -7 -7 -0 -8 -3 -8 -2 -0 -0 -9 -5 -7 -2 -0 -1 -1 -3 -9 -2 -4 -4 -1 -4 -9 -2 -9 -1 -1 -9 -0 -2 -7 -9 -7 -9 -6 -7 -7 -7 -6 -7 -9 -4 -7 -1 -1 -6 -1 -1 -1 -1 -6 -3 -1 -1 -5 -6 -1 -3 -8 -1 -6 -9 -3 -9 -9 -5 -0 -5 -9 -6 -3 -0 -2 -2 -2 -4 -2 -0 -6 -7 -7 -0 -4 -7 -3 -5 -8 -7 -4 -0 -7 -4 -2 -4 -2 -9 -0 -6 -0 -4 -4 -7 -8 -0 -9 -9 -6 -1 -6 -6 -9 -9 -1 -3 -8 -0 -9 -4 -4 -9 -0 -0 -8 -1 -1 -0 -2 -5 -2 -0 -9 -2 -3 -6 -2 -0 -5 -9 -2 -9 -4 -1 -5 -1 -9 -1 -6 -4 -2 -1 -5 -9 -6 -0 -4 -4 -1 -3 -3 -3 -0 -4 -1 -5 -6 -1 -2 -0 -7 -8 -6 -4 -1 -2 -8 -4 -4 -8 -2 -1 -1 -9 -5 -1 -9 -0 -2 -7 -1 -6 -0 -7 -4 -4 -4 -5 -1 -7 -9 -6 -4 -5 -6 -9 -1 -4 -7 -9 -7 -8 -0 -8 -6 -9 -2 -7 -1 -2 -8 -1 -1 -9 -5 -8 -8 -6 -0 -7 -6 -4 -6 -3 -2 -6 -0 -9 -1 -6 -5 -2 -7 -3 -9 -7 -1 -0 -6 -9 -7 -6 -4 -0 -5 -0 -9 -7 -1 -3 -6 -4 -4 -9 -7 -7 -4 -2 -2 -1 -1 -5 -3 -5 -9 -7 -9 -3 -4 -8 -7 -7 -1 -1 -9 -9 -4 -4 -3 -0 -3 -9 -8 -1 -6 -4 -0 -6 -2 -9 -0 -6 -3 -6 -6 -6 -5 -1 -0 -9 -3 -6 -3 -8 -0 -1 -2 -0 -3 -2 -5 -7 -9 -1 -9 -8 -9 -4 -8 -9 -8 -8 -9 -1 -5 -1 -1 -6 -7 -0 -2 -8 -7 -4 -5 -5 -4 -6 -8 -1 -4 -0 -9 -4 -3 -7 -9 -3 -0 -2 -9 -6 -3 -3 -1 -2 -3 -4 -6 -7 -9 -3 -6 -7 -9 -3 -3 -1 -2 -4 -5 -9 -9 -0 -1 -9 -7 -6 -8 -7 -8 -0 -6 -7 -9 -6 -7 -1 -2 -7 -8 -6 -0 -8 -1 -1 -7 -7 -3 -5 -3 -7 -6 -4 -0 -4 -1 -9 -1 -5 -2 -1 -6 -1 -0 -9 -6 -6 -0 -2 -1 -7 -9 -5 -8 -8 -7 -8 -3 -0 -2 -1 -9 -9 -9 -1 -3 -3 -6 -9 -0 -3 -7 -4 -1 -5 -1 -7 -5 -4 -2 -5 -0 -6 -4 -1 -9 -7 -9 -6 -7 -8 -0 -2 -3 -9 -8 -7 -2 -3 -4 -9 -5 -6 -8 -6 -6 -1 -2 -8 -1 -7 -6 -9 -1 -8 -7 -6 -2 -2 -7 -3 -0 -4 -6 -8 -0 -1 -7 -3 -2 -0 -8 -8 -3 -5 -4 -1 -8 -6 -4 -1 -0 -1 -1 -0 -2 -4 -7 -6 -4 -3 -8 -6 -4 -6 -9 -1 -4 -6 -1 -6 -9 -3 -7 -4 -9 -1 -3 -8 -2 -9 -4 -9 -5 -8 -8 -9 -2 -6 -1 -5 -5 -3 -6 -7 -0 -3 -4 -2 -6 -7 -6 -1 -5 -7 -7 -2 -7 -3 -3 -3 -9 -1 -2 -1 -1 -1 -1 -6 -0 -6 -9 -6 -9 -6 -6 -1 -1 -0 -0 -7 -6 -9 -5 -1 -7 -6 -9 -7 -4 -8 -2 -3 -5 -8 -6 -2 -2 -1 -0 -8 -9 -2 -4 -4 -0 -0 -9 -6 -8 -0 -3 -9 -7 -9 -7 -9 -7 -3 -7 -2 -8 -2 -3 -8 -6 -1 -2 -7 -2 -1 -2 -7 -1 -4 -0 -5 -3 -5 -5 -3 -3 -8 -6 -9 -9 -0 -2 -5 -7 -9 -6 -8 -6 -2 -3 -1 -7 -3 -8 -4 -9 -9 -0 -3 -8 -7 -4 -8 -2 -8 -7 -7 -5 -7 -8 -6 -9 -5 -1 -5 -9 -9 -0 -4 -9 -7 -4 -7 -9 -0 -1 -4 -3 -5 -9 -0 -9 -4 -4 -8 -6 -1 -2 -1 -1 -9 -2 -7 -7 -0 -1 -5 -1 -6 -9 -8 -3 -4 -0 -3 -1 -0 -5 -3 -9 -8 -1 -7 -8 -3 -6 -8 -1 -1 -7 -1 -4 -5 -0 -8 -9 -6 -0 -2 -7 -1 -6 -1 -0 -1 -2 -1 -0 -5 -4 -5 -1 -2 -1 -1 -2 -7 -3 -3 -6 -0 -2 -8 -5 -9 -8 -9 -3 -5 -3 -4 -0 -6 -6 -3 -5 -4 -6 -9 -1 -2 -3 -9 -0 -3 -4 -9 -6 -8 -6 -9 -3 -8 -4 -8 -4 -1 -1 -7 -3 -8 -1 -2 -3 -1 -9 -4 -7 -2 -4 -0 -1 -4 -3 -6 -2 -4 -1 -5 -9 -7 -1 -7 -6 -6 -1 -6 -7 -4 -8 -2 -1 -0 -9 -6 -2 -5 -5 -3 -9 -0 -6 -2 -5 -6 -0 -3 -4 -3 -6 -7 -6 -0 -3 -5 -5 -8 -4 -0 -6 -9 -5 -6 -0 -1 -7 -0 -7 -5 -6 -4 -3 -4 -4 -6 -2 -2 -4 -7 -7 -0 -7 -8 -7 -4 -9 -2 -4 -7 -1 -3 -9 -4 -0 -1 -2 -9 -7 -9 -9 -3 -4 -5 -5 -1 -4 -5 -6 -1 -2 -8 -8 -4 -6 -5 -9 -6 -1 -0 -5 -4 -0 -3 -1 -1 -5 -5 -3 -1 -2 -4 -6 -9 -9 -4 -1 -7 -9 -0 -4 -1 -1 -9 -3 -6 -2 -2 -1 -6 -7 -7 -1 -7 -3 -0 -1 -1 -1 -3 -1 -1 -5 -2 -7 -1 -2 -1 -8 -8 -0 -7 -5 -5 -4 -0 -8 -7 -7 -2 -4 -5 -8 -2 -0 -7 -4 -1 -1 -1 -1 -5 -4 -2 -1 -0 -2 -4 -7 -0 -2 -8 -0 -2 -1 -9 -7 -3 -3 -4 -4 -1 -1 -4 -2 -3 -1 -0 -9 -8 -5 -9 -8 -6 -1 -3 -1 -6 -3 -7 -6 -1 -7 -3 -3 -5 -7 -7 -6 -0 -8 -1 -7 -9 -7 -3 -2 -1 -3 -9 -4 -5 -1 -9 -7 -7 -2 -3 -4 -8 -0 -9 -4 -1 -1 -7 -2 -6 -6 -4 -1 -0 -9 -2 -1 -3 -7 -9 -0 -2 -8 -5 -8 -9 -9 -7 -5 -6 -8 -7 -4 -7 -0 -1 -7 -3 -5 -6 -9 -9 -5 -3 -1 -2 -0 -8 -1 -4 -1 -1 -1 -8 -9 -9 -7 -9 -6 -9 -6 -2 -4 -4 -2 -1 -8 -7 -5 -4 -6 -2 -1 -6 -7 -1 -9 -0 -0 -5 -8 -9 -7 -2 -0 -5 -9 -2 -2 -4 -2 -4 -3 -0 -1 -8 -5 -1 -8 -2 -1 -3 -2 -4 -0 -4 -1 -8 -3 -7 -9 -5 -8 -8 -6 -4 -5 -7 -4 -9 -6 -8 -8 -6 -6 -5 -7 -9 -9 -4 -2 -3 -6 -6 -0 -0 -6 -6 -9 -1 -4 -4 -7 -3 -7 -3 -2 -7 -8 -4 -5 -6 -2 -0 -3 -9 -5 -0 -0 -7 -8 -8 -3 -5 -8 -6 -3 -7 -5 -0 -2 -7 -8 -6 -1 -5 -3 -4 -4 -3 -4 -1 -3 -3 -8 -2 -1 -5 -7 -1 -7 -4 -9 -3 -1 -7 -8 -3 -6 -8 -9 -5 -7 -2 -8 -8 -8 -7 -2 -9 -7 -8 -1 -7 -8 -2 -0 -5 -1 -0 -6 -9 -6 -4 -9 -6 -9 -8 -3 -1 -6 -9 -9 -4 -9 -6 -8 -5 -8 -1 -9 -3 -9 -3 -1 -8 -0 -5 -2 -7 -1 -0 -5 -2 -4 -9 -3 -8 -9 -6 -6 -2 -8 -6 -7 -0 -0 -3 -3 -6 -5 -1 -1 -0 -9 -3 -1 -5 -8 -3 -2 -6 -8 -3 -8 -7 -4 -2 -9 -7 -3 -9 -8 -2 -3 -5 -1 -0 -9 -9 -2 -3 -7 -7 -9 -7 -8 -6 -0 -5 -4 -3 -7 -4 -1 -3 -4 -8 -7 -0 -0 -5 -6 -4 -5 -1 -9 -9 -2 -7 -7 -9 -2 -9 -8 -2 -1 -8 -2 -3 -5 -5 -3 -2 -0 -9 -8 -6 -1 -2 -0 -1 -1 -5 -6 -8 -8 -1 -3 -9 -0 -0 -3 -2 -4 -8 -9 -8 -4 -1 -9 -0 -9 -9 -2 -9 -4 -4 -7 -9 -9 -1 -2 -0 -5 -3 -9 -6 -7 -2 -5 -4 -4 -0 -1 -0 -9 -4 -0 -1 -9 -6 -0 -6 -1 -9 -3 -7 -8 -2 -7 -9 -2 -8 -7 -5 -6 -4 -9 -8 -7 -0 -1 -1 -6 -9 -6 -3 -2 -6 -8 -5 -5 -5 -2 -8 -3 -6 -2 -6 -9 -6 -5 -2 -0 -5 -8 -7 -4 -9 -7 -0 -2 -1 -9 -0 -8 -1 -0 -6 -2 -5 -0 -9 -0 -8 -5 -4 -6 -5 -3 -8 -7 -0 -9 -1 -4 -1 -5 -2 -2 -4 -2 -9 -8 -7 -1 -8 -3 -4 -7 -1 -9 -0 -9 -8 -7 -9 -4 -1 -9 -7 -0 -0 -5 -7 -4 -0 -6 -5 -4 -2 -5 -5 -5 -7 -1 -5 -3 -1 -8 -0 -9 -4 -0 -1 -6 -8 -0 -6 -2 -3 -4 -4 -2 -5 -6 -2 -1 -6 -1 -5 -9 -1 -7 -9 -0 -7 -9 -4 -2 -6 -0 -6 -6 -1 -7 -2 -8 -0 -6 -0 -1 -9 -9 -3 -7 -0 -2 -4 -6 -2 -1 -2 -1 -7 -6 -9 -0 -0 -1 -4 -8 -7 -3 -8 -6 -9 -3 -1 -3 -7 -9 -6 -0 -1 -7 -1 -1 -4 -1 -6 -6 -3 -1 -8 -1 -9 -6 -2 -1 -0 -1 -6 -7 -9 -0 -5 -1 -3 -6 -6 -1 -4 -9 -4 -5 -5 -2 -6 -6 -3 -4 -3 -4 -7 -0 -7 -0 -8 -2 -0 -0 -7 -7 -1 -0 -5 -2 -2 -3 -9 -1 -7 -6 -8 -3 -2 -0 -1 -5 -8 -2 -6 -0 -0 -5 -9 -0 -5 -6 -6 -4 -2 -7 -1 -2 -9 -5 -8 -7 -4 -9 -2 -8 -9 -8 -3 -3 -7 -3 -2 -0 -4 -9 -0 -3 -7 -6 -2 -0 -0 -7 -2 -1 -7 -1 -0 -8 -6 -0 -5 -7 -9 -8 -1 -5 -1 -9 -6 -3 -2 -0 -6 -8 -7 -0 -3 -9 -9 -0 -9 -5 -7 -6 -2 -2 -5 -3 -8 -5 -2 -1 -1 -5 -4 -6 -0 -2 -1 -2 -0 -7 -1 -1 -1 -7 -9 -0 -5 -9 -0 -8 -1 -7 -4 -2 -7 -1 -9 -3 -3 -7 -9 -4 -2 -7 -3 -7 -2 -5 -9 -0 -2 -6 -8 -7 -8 -8 -7 -0 -2 -9 -4 -0 -1 -7 -6 -7 -2 -3 -7 -6 -9 -9 -0 -3 -6 -4 -4 -2 -3 -1 -7 -6 -3 -0 -7 -0 -2 -7 -7 -7 -0 -0 -1 -9 -0 -6 -9 -7 -8 -1 -5 -1 -1 -2 -3 -9 -0 -0 -5 -2 -2 -3 -0 -9 -9 -9 -8 -2 -5 -1 -1 -5 -2 -8 -1 -5 -1 -8 -5 -3 -6 -7 -9 -1 -8 -8 -2 -1 -8 -8 -0 -9 -0 -2 -3 -5 -6 -0 -0 -0 -8 -0 -6 -3 -3 -7 -2 -5 -6 -8 -7 -5 -8 -0 -2 -7 -4 -0 -1 -3 -1 -0 -0 -0 -9 -5 -3 -0 -3 -7 -0 -6 -8 -9 -2 -6 -7 -7 -3 -1 -8 -7 -6 -3 -2 -6 -4 -9 -5 -8 -2 -7 -3 -2 -4 -8 -4 -9 -4 -1 -1 -6 -8 -9 -5 -1 -7 -3 -5 -0 -1 -3 -4 -5 -6 -2 -1 -9 -4 -9 -6 -7 -0 -1 -6 -8 -4 -3 -5 -4 -1 -6 -4 -5 -1 -2 -6 -9 -2 -4 -7 -0 -2 -1 -8 -1 -7 -7 -5 -3 -2 -8 -7 -5 -1 -4 -9 -4 -1 -7 -9 -7 -0 -6 -0 -2 -8 -2 -9 -4 -3 -0 -3 -8 -9 -1 -3 -5 -9 -2 -9 -1 -8 -1 -6 -0 -4 -8 -0 -9 -1 -0 -5 -9 -7 -7 -5 -8 -4 -7 -9 -7 -9 -6 -9 -5 -8 -4 -0 -0 -1 -9 -6 -6 -1 -6 -0 -2 -1 -8 -5 -7 -9 -4 -1 -4 -6 -2 -8 -0 -6 -5 -6 -1 -1 -3 -1 -7 -0 -3 -3 -5 -8 -7 -2 -3 -3 -7 -3 -9 -9 -8 -6 -6 -0 -5 -5 -9 -3 -0 -6 -1 -1 -3 -2 -6 -1 -5 -3 -2 -3 -8 -0 -0 -0 -1 -5 -2 -8 -7 -1 -0 -4 -9 -2 -3 -9 -7 -4 -4 -9 -6 -9 -9 -3 -9 -8 -1 -0 -6 -9 -1 -9 -4 -0 -9 -5 -0 -8 -9 -9 -4 -3 -1 -5 -5 -0 -6 -6 -6 -5 -6 -4 -4 -0 -4 -8 -5 -9 -4 -6 -4 -5 -8 -5 -7 -4 -1 -1 -6 -8 -3 -1 -0 -3 -5 -3 -7 -7 -1 -9 -9 -7 -3 -5 -9 -6 -2 -5 -2 -2 -8 -6 -5 -0 -7 -7 -3 -9 -8 -5 -0 -8 -9 -0 -6 -3 -3 -5 -9 -2 -6 -1 -3 -1 -8 -8 -1 -2 -0 -3 -5 -0 -1 -8 -0 -3 -3 -9 -8 -4 -1 -1 -3 -5 -1 -7 -4 -1 -5 -9 -9 -0 -7 -7 -6 -4 -1 -6 -1 -7 -8 -2 -1 -9 -4 -0 -9 -9 -3 -4 -2 -4 -7 -3 -9 -7 -1 -6 -5 -7 -8 -0 -1 -9 -6 -2 -6 -1 -0 -2 -4 -9 -6 -1 -1 -2 -8 -2 -6 -4 -7 -7 -1 -6 -9 -2 -9 -2 -7 -8 -6 -6 -4 -6 -5 -5 -2 -5 -7 -6 -7 -7 -9 -3 -0 -8 -9 -4 -5 -3 -8 -1 -3 -0 -9 -5 -1 -2 -0 -6 -3 -5 -9 -1 -5 -9 -9 -8 -0 -4 -5 -6 -6 -0 -6 -5 -1 -2 -6 -0 -2 -2 -9 -8 -1 -6 -2 -1 -9 -4 -8 -4 -1 -9 -9 -7 -1 -6 -7 -9 -9 -2 -4 -4 -7 -5 -9 -8 -6 -3 -6 -7 -2 -4 -6 -1 -4 -1 -9 -1 -6 -5 -6 -8 -5 -5 -9 -6 -0 -6 -9 -2 -5 -7 -6 -5 -2 -7 -7 -3 -5 -6 -6 -5 -9 -9 -5 -4 -0 -5 -5 -1 -8 -1 -2 -1 -1 -2 -3 -6 -8 -2 -1 -2 -5 -9 -2 -1 -2 -8 -6 -8 -8 -6 -0 -0 -7 -6 -2 -4 -5 -2 -9 -7 -5 -4 -6 -8 -1 -8 -5 -9 -1 -9 -3 -0 -9 -8 -8 -0 -5 -7 -3 -1 -8 -9 -3 -7 -0 -5 -7 -1 -1 -8 -8 -0 -4 -9 -6 -1 -8 -9 -6 -6 -7 -2 -9 -0 -8 -3 -3 -1 -9 -7 -6 -1 -3 -0 -2 -8 -2 -6 -5 -9 -7 -1 -7 -1 -5 -5 -1 -6 -1 -7 -2 -9 -9 -8 -1 -9 -5 -1 -4 -5 -2 -5 -1 -9 -0 -7 -1 -7 -3 -0 -6 -0 -6 -8 -5 -6 -1 -1 -1 -0 -7 -3 -3 -7 -4 -6 -7 -3 -1 -6 -1 -8 -9 -7 -6 -9 -1 -1 -4 -9 -1 -4 -1 -8 -2 -3 -6 -7 -1 -3 -4 -1 -0 -0 -8 -9 -6 -3 -0 -5 -5 -9 -0 -6 -4 -6 -0 -2 -0 -9 -1 -9 -7 -3 -2 -9 -3 -7 -4 -3 -8 -7 -5 -7 -8 -6 -0 -1 -6 -3 -9 -5 -0 -6 -7 -3 -1 -5 -5 -9 -8 -8 -1 -5 -1 -3 -7 -1 -2 -9 -5 -4 -6 -7 -3 -2 -0 -9 -5 -0 -2 -9 -0 -1 -1 -0 -5 -5 -3 -6 -9 -6 -1 -1 -7 -3 -0 -6 -7 -5 -0 -1 -1 -1 -5 -4 -5 -2 -4 -2 -8 -9 -1 -3 -5 -1 -7 -6 -5 -1 -1 -9 -4 -0 -7 -8 -5 -9 -2 -9 -2 -1 -5 -1 -0 -4 -3 -9 -8 -7 -0 -4 -9 -8 -2 -7 -7 -0 -1 -7 -4 -5 -7 -0 -3 -9 -0 -6 -4 -3 -7 -3 -7 -4 -9 -9 -7 -9 -1 -3 -6 -5 -8 -1 -0 -8 -9 -0 -1 -0 -8 -7 -5 -4 -4 -1 -2 -2 -7 -1 -2 -0 -2 -0 -6 -8 -7 -1 -3 -3 -1 -3 -8 -0 -5 -8 -1 -1 -9 -9 -1 -1 -3 -2 -2 -3 -4 -0 -1 -5 -6 -3 -3 -3 -9 -7 -1 -0 -5 -8 -7 -3 -9 -1 -9 -2 -5 -8 -9 -6 -5 -7 -2 -6 -2 -9 -2 -2 -0 -2 -0 -5 -1 -9 -8 -1 -5 -7 -1 -8 -4 -1 -9 -3 -1 -1 -8 -6 -4 -2 -0 -1 -0 -7 -2 -7 -8 -3 -1 -7 -1 -2 -4 -3 -1 -6 -5 -0 -7 -9 -1 -5 -9 -7 -5 -3 -9 -7 -2 -2 -9 -6 -1 -1 -3 -9 -0 -0 -9 -6 -0 -6 -4 -2 -9 -5 -3 -6 -6 -1 -1 -2 -6 -1 -6 -7 -2 -0 -1 -8 -9 -1 -7 -8 -7 -2 -7 -0 -0 -1 -5 -5 -8 -9 -4 -5 -4 -9 -9 -2 -0 -3 -1 -7 -1 -1 -4 -7 -2 -4 -3 -3 -5 -3 -8 -0 -8 -9 -6 -1 -9 -0 -8 -6 -6 -5 -9 -0 -2 -2 -9 -9 -8 -5 -7 -1 -8 -5 -1 -0 -4 -2 -4 -7 -3 -1 -9 -5 -0 -9 -9 -1 -2 -4 -1 -6 -9 -6 -3 -6 -4 -5 -9 -9 -0 -7 -7 -6 -6 -6 -0 -7 -4 -5 -6 -3 -9 -0 -0 -4 -2 -1 -5 -3 -0 -1 -6 -6 -7 -1 -2 -0 -9 -2 -4 -1 -5 -4 -9 -1 -6 -1 -7 -2 -1 -5 -0 -7 -1 -3 -2 -1 -1 -8 -4 -9 -5 -4 -0 -4 -6 -2 -0 -1 -6 -9 -6 -5 -8 -2 -5 -2 -1 -7 -5 -0 -0 -8 -8 -0 -0 -7 -3 -1 -3 -9 -5 -1 -3 -7 -8 -9 -0 -8 -2 -8 -0 -7 -1 -7 -6 -3 -0 -6 -4 -3 -9 -6 -7 -4 -2 -0 -9 -2 -2 -6 -1 -1 -6 -4 -5 -2 -3 -6 -9 -9 -5 -5 -2 -4 -2 -1 -5 -3 -8 -6 -9 -2 -1 -1 -4 -6 -5 -1 -1 -7 -3 -8 -3 -8 -1 -1 -9 -8 -1 -6 -0 -4 -2 -2 -8 -5 -3 -4 -3 -2 -7 -0 -3 -9 -5 -4 -7 -4 -8 -0 -6 -9 -3 -1 -5 -4 -5 -0 -1 -7 -0 -4 -5 -3 -8 -0 -6 -1 -3 -6 -9 -6 -5 -9 -7 -1 -5 -6 -5 -2 -5 -0 -6 -2 -1 -9 -9 -1 -6 -3 -3 -3 -7 -2 -9 -8 -5 -0 -1 -6 -6 -0 -1 -1 -8 -7 -5 -4 -9 -7 -0 -8 -8 -6 -7 -1 -4 -3 -6 -8 -8 -1 -1 -6 -9 -8 -1 -1 -1 -6 -1 -6 -9 -3 -5 -0 -5 -7 -7 -5 -7 -5 -5 -6 -0 -0 -1 -3 -4 -1 -8 -8 -7 -7 -2 -8 -6 -4 -6 -4 -8 -0 -6 -6 -1 -5 -1 -0 -6 -1 -6 -7 -1 -3 -2 -4 -0 -7 -9 -3 -4 -4 -3 -2 -5 -0 -9 -5 -5 -6 -8 -5 -6 -4 -9 -8 -6 -0 -9 -9 -1 -7 -3 -1 -7 -9 -9 -9 -2 -8 -0 -5 -1 -9 -3 -2 -4 -3 -1 -5 -8 -1 -4 -4 -1 -9 -7 -5 -6 -3 -6 -0 -3 -9 -1 -9 -4 -5 -1 -3 -9 -9 -4 -3 -2 -8 -1 -8 -1 -4 -1 -9 -0 -4 -0 -9 -0 -4 -1 -5 -0 -8 -0 -9 -0 -8 -1 -8 -7 -1 -8 -1 -6 -4 -0 -9 -6 -0 -7 -9 -2 -2 -5 -1 -4 -3 -3 -6 -9 -1 -0 -7 -2 -5 -4 -7 -8 -1 -9 -9 -3 -4 -3 -3 -8 -1 -7 -0 -8 -5 -7 -2 -1 -8 -6 -1 -7 -7 -9 -1 -0 -6 -5 -0 -2 -3 -9 -1 -7 -0 -8 -6 -1 -4 -9 -5 -7 -2 -4 -2 -3 -8 -2 -1 -7 -5 -1 -4 -5 -1 -8 -1 -7 -4 -4 -1 -3 -1 -0 -5 -3 -9 -7 -6 -9 -1 -1 -5 -1 -8 -4 -2 -5 -5 -8 -7 -2 -4 -0 -7 -9 -8 -6 -3 -8 -7 -4 -6 -2 -6 -4 -2 -2 -8 -8 -3 -1 -9 -1 -4 -0 -2 -1 -0 -0 -0 -9 -2 -3 -8 -3 -1 -7 -3 -0 -2 -0 -6 -0 -2 -7 -4 -5 -6 -2 -8 -9 -3 -0 -0 -0 -7 -9 -1 -6 -8 -1 -4 -2 -1 -2 -0 -6 -7 -4 -3 -5 -2 -0 -0 -4 -4 -9 -8 -5 -1 -9 -1 -2 -1 -5 -4 -9 -9 -6 -1 -8 -1 -5 -9 -9 -5 -6 -7 -6 -3 -8 -3 -4 -2 -3 -6 -3 -6 -5 -3 -4 -2 -6 -0 -1 -9 -1 -7 -7 -2 -7 -2 -9 -1 -0 -4 -6 -2 -5 -6 -0 -3 -1 -4 -8 -2 -1 -5 -5 -7 -4 -3 -0 -3 -7 -0 -2 -8 -6 -1 -1 -4 -0 -9 -0 -4 -1 -5 -3 -9 -4 -6 -5 -0 -5 -0 -1 -4 -8 -1 -0 -5 -8 -9 -6 -5 -4 -5 -5 -8 -3 -1 -9 -9 -2 -0 -3 -7 -3 -4 -3 -0 -6 -6 -5 -9 -3 -9 -2 -5 -9 -6 -3 -6 -9 -8 -2 -6 -3 -4 -1 -1 -3 -5 -8 -0 -4 -5 -4 -0 -2 -0 -6 -9 -1 -2 -3 -1 -1 -0 -1 -4 -4 -0 -6 -7 -1 -7 -2 -3 -6 -4 -3 -1 -8 -3 -9 -0 -2 -9 -9 -1 -3 -8 -6 -3 -7 -8 -0 -2 -9 -9 -9 -1 -0 -1 -5 -5 -4 -2 -4 -5 -3 -8 -6 -7 -9 -5 -2 -5 -1 -1 -2 -5 -0 -6 -9 -8 -8 -7 -1 -9 -9 -9 -2 -1 -3 -9 -6 -3 -4 -6 -1 -0 -4 -9 -1 -5 -3 -7 -9 -7 -6 -7 -6 -5 -9 -9 -6 -6 -9 -0 -4 -7 -7 -8 -9 -3 -0 -3 -2 -2 -9 -3 -0 -7 -9 -6 -1 -0 -8 -3 -3 -5 -2 -1 -2 -2 -2 -9 -1 -8 -3 -3 -5 -7 -6 -2 -2 -0 -1 -7 -5 -3 -7 -0 -1 -1 -9 -9 -9 -1 -1 -4 -3 -7 -2 -7 -3 -4 -7 -1 -0 -5 -6 -9 -7 -7 -0 -3 -9 -5 -4 -4 -5 -9 -9 -9 -4 -5 -2 -7 -3 -0 -3 -3 -8 -1 -4 -8 -1 -2 -0 -1 -6 -9 -0 -7 -7 -3 -6 -1 -0 -6 -5 -9 -3 -4 -7 -5 -6 -4 -2 -2 -2 -5 -3 -7 -8 -0 -8 -6 -1 -6 -4 -4 -0 -9 -0 -3 -5 -1 -7 -1 -4 -1 -8 -4 -9 -8 -0 -3 -5 -7 -4 -4 -6 -6 -8 -6 -9 -3 -1 -1 -6 -1 -9 -9 -3 -7 -7 -2 -7 -2 -2 -0 -6 -7 -0 -1 -5 -6 -2 -6 -2 -5 -5 -7 -6 -9 -7 -9 -4 -1 -3 -2 -6 -1 -5 -9 -9 -7 -8 -7 -0 -1 -4 -5 -7 -6 -5 -6 -0 -4 -7 -5 -1 -6 -1 -1 -9 -9 -8 -3 -5 -1 -7 -4 -4 -2 -9 -9 -7 -1 -7 -5 -2 -6 -2 -1 -4 -1 -5 -3 -9 -7 -9 -4 -3 -2 -6 -9 -1 -3 -5 -7 -0 -3 -9 -3 -5 -9 -1 -6 -8 -7 -2 -0 -0 -5 -2 -1 -8 -4 -4 -4 -4 -2 -4 -5 -9 -3 -9 -6 -7 -4 -0 -3 -4 -8 -7 -6 -1 -3 -2 -1 -0 -3 -0 -3 -5 -1 -4 -2 -8 -8 -0 -2 -8 -3 -9 -5 -9 -7 -8 -2 -6 -1 -2 -4 -1 -3 -4 -3 -2 -0 -1 -8 -4 -6 -8 -8 -7 -8 -5 -1 -2 -2 -0 -7 -6 -9 -1 -8 -7 -6 -2 -4 -6 -0 -2 -3 -5 -0 -5 -7 -4 -1 -7 -8 -9 -9 -1 -5 -0 -2 -0 -3 -3 -6 -4 -9 -4 -8 -6 -5 -2 -9 -0 -2 -1 -9 -8 -2 -5 -4 -7 -4 -8 -3 -4 -5 -2 -6 -4 -1 -3 -0 -2 -1 -2 -7 -2 -2 -6 -6 -0 -1 -4 -6 -1 -0 -2 -9 -8 -6 -1 -1 -9 -5 -6 -7 -6 -7 -5 -0 -3 -9 -9 -2 -6 -6 -9 -5 -9 -3 -2 -7 -4 -1 -4 -8 -7 -8 -4 -1 -8 -5 -6 -0 -8 -9 -3 -2 -6 -4 -6 -6 -5 -1 -8 -6 -8 -3 -7 -1 -1 -3 -6 -9 -4 -6 -0 -3 -9 -2 -6 -3 -7 -4 -3 -4 -1 -7 -2 -5 -6 -9 -6 -6 -3 -9 -4 -1 -8 -2 -3 -6 -0 -7 -7 -7 -3 -1 -0 -1 -0 -6 -0 -6 -7 -5 -5 -1 -9 -2 -5 -3 -3 -3 -7 -1 -0 -9 -2 -3 -2 -9 -3 -1 -8 -0 -1 -3 -8 -5 -0 -1 -9 -8 -1 -0 -1 -2 -6 -8 -2 -7 -4 -7 -7 -0 -1 -9 -9 -6 -1 -6 -7 -1 -3 -5 -3 -9 -0 -8 -2 -9 -4 -9 -2 -6 -1 -7 -9 -9 -0 -9 -7 -1 -9 -2 -7 -4 -6 -3 -3 -9 -7 -8 -1 -1 -0 -7 -9 -2 -5 -5 -5 -6 -5 -0 -9 -5 -5 -0 -0 -1 -7 -0 -1 -6 -9 -6 -2 -6 -9 -0 -0 -5 -3 -4 -6 -4 -2 -0 -7 -1 -2 -6 -2 -2 -6 -7 -5 -0 -2 -8 -4 -0 -9 -2 -6 -5 -9 -7 -8 -9 -5 -3 -9 -1 -1 -2 -5 -9 -4 -2 -5 -0 -1 -4 -0 -9 -6 -6 -0 -7 -8 -9 -7 -5 -3 -8 -9 -9 -1 -1 -6 -3 -3 -5 -0 -1 -1 -7 -8 -5 -7 -6 -5 -5 -9 -9 -0 -9 -1 -1 -6 -0 -4 -8 -2 -6 -7 -9 -5 -9 -6 -9 -7 -1 -8 -8 -4 -7 -2 -3 -7 -9 -0 -0 -1 -9 -5 -2 -8 -9 -1 -4 -5 -7 -8 -5 -5 -6 -0 -6 -8 -9 -2 -2 -0 -8 -8 -7 -7 -5 -7 -2 -7 -1 -4 -6 -8 -4 -9 -5 -1 -1 -7 -6 -9 -8 -1 -6 -6 -4 -3 -3 -0 -5 -0 -3 -1 -6 -2 -6 -1 -6 -7 -6 -0 -6 -4 -8 -4 -6 -7 -4 -8 -8 -7 -4 -3 -1 -0 -9 -4 -0 -1 -8 -9 -6 -0 -6 -9 -9 -1 -9 -4 -2 -0 -9 -9 -1 -2 -9 -6 -5 -8 -1 -7 -5 -7 -2 -5 -8 -0 -0 -6 -5 -9 -3 -5 -4 -0 -3 -8 -3 -6 -9 -0 -0 -5 -8 -9 -6 -7 -2 -2 -8 -9 -6 -1 -6 -4 -4 -6 -6 -4 -0 -0 -9 -6 -4 -9 -9 -3 -0 -3 -1 -2 -1 -5 -1 -9 -4 -5 -3 -1 -9 -8 -2 -0 -2 -9 -2 -3 -3 -7 -6 -9 -6 -1 -3 -0 -1 -3 -7 -7 -9 -6 -9 -4 -5 -5 -6 -8 -3 -8 -3 -5 -7 -6 -3 -7 -7 -5 -4 -5 -1 -2 -8 -8 -7 -1 -5 -6 -5 -2 -5 -5 -1 -5 -6 -1 -4 -3 -0 -0 -3 -4 -2 -9 -0 -5 -2 -9 -3 -0 -6 -3 -2 -9 -6 -1 -8 -5 -7 -0 -5 -4 -1 -8 -8 -2 -9 -2 -0 -1 -4 -9 -7 -6 -3 -8 -4 -5 -0 -6 -6 -0 -5 -9 -0 -7 -4 -8 -9 -5 -9 -7 -9 -0 -1 -1 -1 -2 -0 -7 -5 -0 -6 -0 -8 -7 -1 -9 -8 -5 -2 -6 -1 -6 -9 -2 -3 -9 -8 -8 -9 -0 -2 -9 -4 -8 -5 -1 -0 -9 -0 -1 -7 -9 -4 -0 -1 -3 -9 -8 -9 -4 -5 -0 -1 -5 -8 -8 -1 -6 -9 -7 -0 -1 -7 -5 -6 -4 -6 -1 -9 -9 -9 -3 -9 -6 -9 -0 -0 -1 -5 -9 -3 -3 -2 -1 -1 -2 -4 -3 -1 -8 -5 -2 -3 -3 -5 -4 -8 -0 -5 -3 -5 -9 -3 -5 -8 -5 -1 -6 -0 -8 -9 -8 -0 -4 -1 -0 -1 -3 -1 -8 -6 -3 -1 -1 -0 -5 -8 -6 -9 -5 -1 -6 -1 -1 -6 -4 -3 -8 -6 -9 -4 -2 -8 -6 -7 -2 -7 -7 -6 -8 -2 -2 -0 -7 -0 -7 -5 -0 -9 -9 -6 -4 -5 -6 -1 -2 -0 -3 -9 -7 -6 -0 -3 -4 -1 -7 -7 -7 -1 -0 -0 -6 -0 -6 -5 -9 -7 -8 -2 -5 -1 -1 -9 -3 -8 -8 -9 -1 -2 -6 -6 -6 -9 -0 -3 -8 -6 -1 -5 -6 -6 -4 -3 -4 -9 -0 -0 -1 -0 -9 -2 -2 -1 -7 -5 -4 -1 -6 -0 -3 -8 -9 -9 -7 -8 -2 -7 -8 -5 -0 -2 -1 -8 -9 -1 -6 -9 -3 -9 -9 -1 -8 -7 -9 -1 -2 -2 -5 -6 -5 -8 -7 -3 -6 -1 -2 -6 -8 -1 -8 -6 -7 -4 -1 -1 -3 -4 -0 -9 -1 -1 -0 -1 -8 -1 -3 -9 -0 -3 -8 -5 -9 -0 -9 -8 -7 -7 -1 -0 -1 -0 -3 -4 -9 -6 -3 -0 -2 -4 -9 -7 -1 -9 -1 -9 -3 -8 -2 -0 -4 -7 -3 -2 -6 -7 -1 -5 -1 -1 -2 -4 -0 -0 -4 -8 -8 -5 -2 -5 -8 -5 -9 -0 -3 -2 -4 -8 -2 -0 -2 -7 -5 -1 -6 -8 -9 -1 -0 -7 -2 -6 -1 -1 -6 -0 -2 -9 -6 -0 -0 -8 -7 -4 -3 -6 -8 -1 -6 -7 -4 -6 -9 -3 -2 -0 -9 -8 -6 -6 -3 -0 -2 -0 -3 -0 -7 -2 -2 -1 -8 -4 -7 -9 -6 -7 -3 -1 -3 -7 -0 -3 -7 -2 -2 -2 -0 -7 -9 -1 -2 -0 -6 -6 -2 -3 -6 -7 -4 -9 -4 -5 -8 -9 -3 -7 -4 -2 -9 -9 -8 -6 -7 -0 -3 -0 -9 -1 -3 -1 -6 -5 -0 -6 -0 -1 -9 -6 -9 -0 -8 -8 -7 -4 -0 -9 -9 -6 -8 -0 -2 -4 -8 -4 -4 -1 -7 -1 -1 -9 -2 -2 -7 -6 -8 -0 -2 -0 -6 -0 -1 -9 -0 -3 -9 -9 -7 -9 -5 -0 -3 -8 -9 -8 -0 -1 -4 -6 -7 -9 -2 -7 -9 -7 -6 -5 -8 -2 -1 -4 -9 -7 -5 -8 -1 -2 -1 -1 -7 -1 -9 -6 -0 -1 -9 -9 -6 -0 -1 -8 -1 -0 -7 -4 -6 -6 -2 -9 -2 -1 -3 -5 -1 -9 -3 -1 -9 -3 -4 -1 -1 -8 -9 -9 -7 -5 -4 -1 -6 -0 -1 -2 -6 -0 -3 -0 -6 -8 -7 -2 -0 -3 -9 -7 -8 -4 -6 -4 -0 -5 -8 -9 -3 -3 -0 -1 -2 -1 -3 -8 -7 -2 -8 -2 -8 -0 -4 -6 -4 -2 -1 -6 -1 -4 -4 -1 -1 -6 -5 -7 -1 -1 -6 -1 -5 -9 -4 -3 -3 -3 -9 -0 -7 -4 -1 -3 -3 -1 -1 -6 -5 -7 -3 -9 -5 -4 -5 -6 -4 -1 -5 -9 -3 -9 -3 -8 -0 -8 -9 -6 -8 -5 -7 -9 -0 -9 -7 -2 -9 -1 -3 -5 -1 -4 -7 -3 -8 -1 -5 -7 -5 -0 -2 -7 -3 -9 -0 -1 -3 -2 -2 -2 -4 -0 -0 -4 -9 -5 -9 -1 -7 -0 -1 -4 -0 -8 -3 -0 -4 -0 -9 -6 -9 -0 -1 -0 -7 -3 -5 -6 -8 -2 -9 -1 -6 -1 -5 -1 -9 -1 -9 -5 -8 -9 -9 -6 -3 -8 -7 -5 -0 -3 -9 -3 -7 -1 -8 -7 -9 -3 -3 -9 -7 -0 -6 -3 -9 -4 -7 -6 -4 -3 -5 -5 -9 -7 -4 -4 -1 -5 -1 -0 -3 -9 -9 -1 -6 -5 -6 -4 -3 -3 -3 -3 -7 -9 -7 -5 -1 -2 -2 -0 -9 -9 -1 -4 -5 -1 -9 -4 -2 -1 -2 -8 -0 -0 -2 -8 -3 -2 -8 -8 -3 -4 -4 -1 -8 -1 -2 -0 -6 -4 -6 -9 -6 -1 -9 -0 -3 -5 -5 -5 -2 -8 -5 -8 -1 -2 -8 -9 -4 -4 -0 -9 -8 -0 -3 -4 -2 -7 -7 -0 -7 -6 -8 -9 -9 -0 -0 -9 -2 -3 -1 -9 -2 -9 -2 -0 -6 -9 -3 -7 -9 -7 -5 -2 -5 -8 -7 -1 -1 -2 -1 -4 -7 -4 -8 -7 -4 -0 -4 -0 -5 -0 -0 -2 -6 -1 -0 -8 -5 -5 -6 -2 -2 -1 -3 -5 -8 -3 -3 -6 -7 -3 -6 -4 -5 -9 -6 -2 -7 -9 -8 -2 -7 -3 -9 -7 -8 -1 -9 -8 -3 -6 -9 -2 -2 -6 -2 -8 -0 -7 -7 -8 -9 -6 -6 -9 -3 -6 -8 -0 -4 -3 -8 -2 -5 -0 -6 -1 -1 -9 -2 -7 -1 -5 -7 -3 -9 -1 -1 -3 -3 -7 -9 -2 -1 -3 -3 -8 -3 -9 -4 -2 -1 -4 -6 -7 -6 -6 -2 -6 -4 -1 -9 -7 -1 -6 -6 -9 -3 -5 -4 -3 -7 -3 -0 -8 -4 -6 -9 -0 -2 -9 -8 -1 -7 -2 -5 -3 -3 -7 -9 -3 -9 -5 -9 -9 -2 -8 -2 -6 -1 -1 -8 -2 -2 -9 -6 -9 -8 -5 -1 -8 -1 -8 -0 -6 -0 -3 -9 -3 -3 -6 -9 -3 -2 -0 -8 -3 -0 -1 -9 -6 -0 -8 -0 -1 -5 -7 -1 -3 -5 -5 -8 -0 -6 -2 -9 -6 -8 -2 -0 -7 -1 -2 -3 -1 -2 -4 -3 -8 -7 -3 -5 -0 -9 -4 -2 -2 -2 -9 -5 -9 -6 -8 -2 -2 -2 -1 -1 -2 -2 -8 -8 -5 -3 -9 -9 -0 -3 -1 -5 -3 -3 -0 -7 -8 -9 -5 -6 -0 -1 -7 -7 -6 -1 -3 -1 -2 -1 -4 -0 -9 -7 -0 -3 -7 -9 -8 -9 -6 -3 -1 -5 -8 -1 -9 -1 -0 -6 -6 -2 -5 -6 -1 -7 -1 -7 -0 -3 -3 -7 -9 -2 -0 -6 -8 -0 -1 -1 -1 -7 -7 -3 -3 -6 -4 -6 -9 -6 -0 -9 -1 -3 -3 -6 -7 -2 -1 -7 -5 -7 -6 -6 -7 -8 -1 -6 -3 -1 -0 -5 -9 -9 -9 -4 -6 -6 -1 -7 -8 -4 -4 -1 -3 -2 -9 -6 -8 -5 -9 -0 -2 -2 -7 -1 -3 -0 -6 -2 -6 -7 -9 -9 -3 -3 -9 -2 -1 -6 -5 -4 -0 -2 -4 -6 -2 -1 -6 -7 -5 -1 -9 -9 -5 -9 -4 -1 -5 -8 -1 -3 -5 -2 -7 -1 -2 -7 -1 -3 -4 -6 -9 -4 -9 -0 -9 -6 -9 -0 -8 -5 -9 -0 -3 -3 -0 -6 -8 -9 -0 -5 -9 -7 -6 -7 -2 -7 -7 -7 -1 -4 -8 -9 -6 -0 -2 -1 -5 -7 -9 -9 -0 -2 -0 -0 -2 -3 -6 -0 -2 -3 -2 -9 -1 -9 -2 -6 -4 -0 -9 -2 -4 -3 -1 -0 -2 -7 -6 -2 -5 -3 -7 -9 -3 -4 -0 -8 -9 -8 -7 -5 -1 -3 -5 -7 -9 -3 -3 -5 -7 -1 -2 -7 -5 -1 -5 -2 -5 -9 -8 -1 -9 -6 -7 -7 -2 -8 -3 -1 -7 -5 -9 -2 -6 -7 -3 -5 -4 -0 -7 -2 -4 -8 -2 -5 -1 -9 -8 -5 -1 -6 -3 -4 -9 -2 -6 -8 -4 -7 -1 -4 -4 -5 -6 -9 -4 -4 -2 -6 -3 -2 -7 -7 -2 -7 -1 -1 -7 -4 -0 -6 -2 -3 -0 -9 -9 -2 -7 -1 -6 -4 -1 -6 -7 -4 -1 -8 -7 -5 -4 -9 -2 -1 -4 -6 -6 -2 -7 -9 -5 -3 -4 -4 -8 -5 -7 -4 -5 -6 -6 -1 -3 -5 -6 -6 -2 -8 -2 -6 -8 -5 -3 -0 -0 -9 -8 -0 -1 -2 -9 -5 -3 -0 -9 -2 -9 -6 -1 -9 -7 -5 -8 -7 -0 -6 -3 -5 -3 -7 -0 -0 -9 -1 -6 -5 -1 -1 -5 -3 -4 -0 -3 -3 -1 -2 -8 -2 -7 -8 -9 -9 -7 -9 -1 -8 -8 -4 -4 -8 -4 -8 -5 -5 -7 -4 -9 -0 -3 -6 -1 -2 -4 -6 -2 -1 -1 -0 -7 -1 -5 -9 -3 -0 -5 -1 -7 -6 -1 -5 -2 -1 -1 -3 -7 -0 -8 -2 -4 -2 -5 -0 -3 -5 -9 -1 -3 -9 -5 -0 -0 -3 -6 -9 -0 -4 -5 -4 -1 -6 -2 -8 -1 -1 -4 -3 -8 -0 -7 -6 -6 -8 -5 -0 -5 -5 -6 -8 -4 -1 -2 -0 -3 -9 -6 -7 -8 -3 -9 -7 -8 -9 -6 -1 -3 -3 -4 -8 -3 -0 -1 -9 -1 -3 -0 -8 -6 -5 -4 -1 -7 -8 -3 -1 -9 -7 -8 -2 -6 -1 -0 -4 -0 -3 -5 -2 -9 -8 -1 -9 -2 -5 -2 -0 -9 -8 -3 -9 -0 -0 -6 -6 -7 -2 -7 -2 -3 -7 -9 -8 -3 -8 -8 -9 -6 -1 -8 -7 -2 -9 -6 -6 -4 -3 -1 -1 -4 -2 -1 -7 -5 -4 -9 -9 -2 -4 -5 -9 -4 -7 -1 -6 -6 -6 -2 -8 -4 -1 -5 -3 -7 -8 -3 -1 -3 -5 -0 -3 -6 -5 -7 -9 -9 -3 -0 -2 -5 -7 -8 -4 -7 -3 -7 -6 -6 -8 -3 -1 -4 -2 -2 -4 -9 -5 -1 -6 -6 -6 -7 -7 -8 -9 -0 -3 -4 -5 -0 -1 -6 -2 -1 -0 -9 -3 -8 -5 -5 -8 -8 -7 -0 -5 -7 -9 -6 -5 -6 -2 -2 -5 -8 -8 -5 -2 -9 -4 -6 -3 -8 -4 -4 -6 -6 -0 -4 -2 -5 -5 -1 -3 -9 -6 -2 -4 -5 -1 -1 -2 -7 -3 -6 -4 -2 -2 -4 -0 -1 -6 -6 -1 -7 -7 -2 -6 -5 -7 -4 -2 -8 -4 -9 -9 -2 -6 -1 -8 -1 -5 -0 -9 -3 -4 -2 -9 -9 -8 -3 -3 -4 -6 -9 -2 -6 -3 -3 -4 -4 -1 -1 -9 -5 -5 -1 -6 -1 -0 -0 -2 -7 -1 -1 -3 -0 -5 -4 -2 -6 -7 -8 -5 -9 -9 -6 -2 -2 -3 -6 -6 -2 -9 -0 -3 -6 -9 -5 -7 -1 -1 -7 -8 -2 -9 -7 -7 -9 -9 -5 -6 -9 -9 -1 -5 -5 -1 -8 -0 -7 -8 -0 -5 -9 -6 -8 -6 -2 -6 -6 -7 -0 -0 -5 -9 -1 -7 -1 -1 -3 -1 -1 -5 -5 -8 -3 -2 -3 -2 -9 -4 -6 -3 -7 -1 -5 -7 -8 -4 -8 -3 -0 -3 -9 -8 -0 -2 -8 -7 -9 -6 -3 -4 -9 -3 -6 -1 -7 -5 -9 -4 -6 -9 -2 -1 -7 -5 -7 -6 -4 -3 -6 -6 -9 -6 -5 -1 -5 -9 -6 -5 -0 -4 -1 -4 -2 -7 -8 -9 -8 -8 -0 -6 -2 -4 -9 -9 -9 -3 -3 -5 -3 -1 -0 -2 -7 -4 -1 -1 -8 -2 -9 -7 -2 -5 -0 -6 -8 -1 -5 -8 -4 -4 -8 -5 -3 -2 -1 -6 -7 -4 -4 -9 -2 -5 -8 -5 -3 -7 -7 -3 -3 -5 -7 -0 -7 -9 -9 -1 -6 -1 -9 -1 -9 -9 -7 -2 -2 -9 -7 -8 -0 -9 -9 -6 -7 -3 -5 -7 -7 -5 -9 -9 -0 -7 -8 -0 -6 -6 -5 -1 -8 -5 -9 -9 -5 -2 -8 -6 -8 -6 -7 -7 -7 -4 -4 -4 -1 -0 -6 -1 -6 -7 -1 -1 -6 -1 -7 -3 -7 -2 -6 -2 -9 -5 -0 -3 -2 -7 -6 -6 -9 -9 -1 -9 -2 -2 -6 -0 -3 -3 -6 -6 -1 -6 -1 -9 -8 -0 -0 -9 -3 -3 -9 -9 -3 -3 -5 -9 -1 -1 -8 -5 -8 -6 -2 -0 -6 -8 -0 -0 -2 -5 -5 -1 -1 -1 -8 -2 -4 -2 -1 -7 -9 -2 -9 -6 -2 -8 -2 -6 -5 -8 -8 -5 -0 -0 -0 -3 -2 -7 -7 -7 -2 -2 -1 -8 -1 -4 -4 -2 -7 -6 -8 -9 -7 -2 -7 -7 -5 -1 -8 -5 -5 -9 -3 -9 -7 -6 -0 -4 -8 -3 -6 -2 -4 -8 -3 -4 -5 -0 -9 -9 -0 -3 -5 -1 -1 -1 -9 -4 -8 -0 -8 -9 -2 -5 -2 -5 -1 -7 -0 -0 -2 -8 -1 -0 -4 -3 -9 -2 -5 -0 -7 -3 -6 -1 -7 -5 -3 -3 -2 -1 -6 -2 -4 -5 -6 -0 -6 -2 -1 -4 -7 -7 -0 -2 -1 -1 -5 -3 -7 -4 -0 -2 -4 -0 -2 -4 -2 -9 -3 -5 -5 -7 -6 -2 -6 -0 -5 -7 -9 -6 -4 -3 -2 -8 -2 -9 -5 -2 -5 -6 -0 -3 -0 -5 -5 -1 -5 -1 -9 -4 -5 -8 -1 -1 -5 -8 -4 -1 -7 -0 -4 -4 -1 -8 -7 -7 -4 -9 -3 -6 -3 -6 -2 -2 -8 -3 -1 -7 -3 -1 -4 -5 -4 -0 -8 -2 -8 -8 -3 -2 -8 -5 -4 -6 -3 -3 -3 -7 -1 -9 -6 -6 -7 -5 -9 -0 -2 -1 -4 -2 -4 -5 -1 -1 -6 -9 -7 -6 -7 -6 -9 -8 -4 -7 -9 -1 -4 -6 -2 -4 -3 -8 -8 -9 -7 -6 -3 -9 -1 -6 -3 -9 -0 -9 -6 -4 -2 -5 -6 -3 -5 -2 -0 -5 -7 -3 -9 -5 -5 -0 -0 -9 -3 -1 -9 -1 -1 -1 -4 -8 -6 -4 -4 -3 -0 -8 -9 -1 -4 -2 -4 -0 -1 -0 -3 -9 -0 -8 -8 -7 -0 -8 -8 -9 -6 -9 -5 -6 -6 -5 -9 -9 -6 -4 -2 -1 -5 -5 -2 -7 -0 -1 -0 -0 -9 -3 -2 -1 -6 -6 -7 -7 -5 -5 -2 -8 -3 -3 -2 -5 -8 -3 -3 -9 -9 -6 -4 -6 -1 -0 -9 -3 -6 -7 -5 -3 -2 -7 -7 -5 -6 -2 -3 -3 -6 -4 -6 -1 -2 -1 -7 -2 -2 -6 -6 -4 -4 -8 -6 -9 -5 -8 -5 -2 -8 -9 -8 -0 -9 -6 -9 -3 -2 -4 -0 -6 -6 -2 -4 -7 -8 -1 -3 -8 -1 -2 -7 -1 -3 -7 -9 -9 -4 -3 -4 -3 -7 -1 -2 -6 -8 -5 -1 -2 -1 -1 -0 -5 -6 -5 -2 -6 -2 -2 -3 -6 -9 -7 -4 -9 -0 -1 -1 -1 -1 -3 -5 -5 -1 -2 -3 -1 -2 -6 -1 -9 -0 -8 -0 -2 -1 -4 -4 -5 -7 -0 -8 -7 -8 -1 -3 -7 -2 -2 -2 -4 -2 -9 -3 -9 -2 -8 -3 -2 -5 -9 -4 -3 -7 -1 -0 -6 -9 -0 -9 -2 -0 -0 -5 -0 -5 -6 -0 -2 -7 -5 -0 -7 -4 -9 -9 -3 -6 -2 -9 -1 -3 -2 -3 -0 -0 -6 -5 -1 -7 -0 -6 -2 -0 -9 -9 -1 -5 -3 -5 -8 -9 -6 -7 -1 -5 -0 -1 -0 -0 -6 -4 -7 -7 -4 -9 -3 -8 -8 -9 -6 -7 -0 -1 -1 -3 -8 -7 -7 -4 -2 -1 -5 -7 -1 -7 -8 -2 -8 -0 -8 -3 -1 -0 -1 -3 -3 -6 -6 -6 -6 -1 -0 -8 -3 -7 -0 -5 -9 -6 -0 -2 -2 -5 -6 -1 -7 -5 -1 -7 -8 -1 -0 -4 -9 -3 -0 -2 -1 -3 -8 -3 -5 -7 -2 -8 -2 -1 -0 -2 -4 -5 -6 -7 -3 -8 -5 -0 -3 -5 -8 -1 -9 -4 -5 -8 -3 -9 -6 -1 -1 -6 -6 -4 -4 -5 -0 -2 -4 -2 -5 -9 -6 -8 -8 -5 -9 -0 -3 -0 -9 -2 -6 -3 -9 -3 -9 -6 -8 -9 -5 -3 -7 -2 -7 -1 -7 -4 -6 -7 -4 -6 -1 -5 -7 -9 -5 -6 -1 -2 -9 -3 -1 -8 -5 -1 -4 -1 -1 -8 -5 -8 -2 -2 -5 -2 -7 -5 -3 -6 -7 -8 -9 -6 -6 -1 -0 -9 -0 -0 -9 -3 -4 -7 -5 -5 -6 -9 -9 -2 -3 -9 -7 -3 -1 -6 -0 -0 -0 -2 -8 -6 -3 -6 -6 -6 -0 -2 -7 -3 -8 -1 -9 -6 -7 -9 -6 -7 -0 -1 -6 -4 -8 -4 -8 -5 -3 -5 -5 -8 -2 -9 -3 -2 -4 -7 -4 -2 -6 -3 -7 -6 -2 -0 -3 -4 -5 -6 -8 -9 -1 -4 -5 -1 -9 -1 -5 -2 -6 -7 -7 -4 -6 -5 -4 -6 -0 -0 -7 -0 -5 -8 -3 -6 -3 -8 -8 -3 -6 -1 -7 -9 -9 -1 -8 -8 -1 -4 -1 -9 -5 -9 -1 -9 -8 -2 -6 -4 -8 -5 -1 -7 -9 -8 -1 -6 -9 -5 -6 -1 -1 -2 -1 -0 -7 -0 -7 -1 -4 -4 -2 -6 -3 -1 -9 -3 -6 -5 -5 -5 -7 -6 -5 -0 -7 -8 -3 -5 -4 -3 -4 -3 -7 -9 -6 -2 -6 -0 -2 -5 -1 -1 -1 -2 -5 -3 -9 -9 -8 -9 -6 -9 -7 -5 -5 -2 -0 -1 -7 -4 -7 -9 -3 -2 -3 -5 -1 -9 -5 -6 -9 -6 -5 -1 -4 -8 -2 -8 -9 -6 -6 -8 -3 -3 -4 -2 -2 -1 -0 -1 -8 -0 -7 -1 -9 -3 -7 -1 -0 -4 -3 -6 -7 -8 -3 -2 -7 -7 -6 -5 -4 -7 -6 -9 -8 -6 -1 -1 -2 -4 -6 -1 -3 -1 -8 -1 -9 -4 -3 -9 -3 -5 -4 -3 -7 -9 -9 -4 -0 -8 -2 -5 -8 -9 -0 -9 -1 -9 -4 -3 -6 -8 -9 -3 -9 -2 -7 -4 -0 -8 -9 -3 -9 -7 -5 -0 -2 -5 -2 -2 -8 -2 -0 -5 -4 -7 -3 -2 -4 -3 -0 -1 -2 -5 -1 -3 -1 -2 -4 -7 -3 -6 -2 -4 -9 -3 -7 -3 -6 -1 -5 -2 -5 -1 -5 -6 -8 -2 -2 -2 -1 -5 -6 -3 -9 -1 -7 -8 -0 -6 -7 -4 -6 -0 -3 -8 -6 -1 -6 -4 -7 -6 -7 -3 -4 -1 -7 -4 -4 -6 -6 -9 -5 -7 -9 -3 -8 -2 -5 -4 -5 -4 -0 -0 -9 -7 -7 -5 -7 -4 -5 -9 -7 -9 -9 -1 -8 -9 -9 -5 -7 -1 -2 -0 -1 -9 -6 -5 -9 -0 -4 -8 -0 -5 -9 -3 -3 -7 -7 -0 -7 -0 -5 -4 -2 -5 -7 -0 -3 -4 -4 -1 -0 -0 -9 -9 -6 -4 -4 -1 -1 -0 -0 -9 -9 -7 -4 -7 -2 -1 -8 -4 -4 -4 -5 -6 -6 -2 -1 -1 -4 -2 -1 -8 -7 -1 -7 -8 -3 -3 -3 -0 -0 -5 -1 -2 -9 -9 -0 -0 -8 -7 -6 -6 -1 -9 -7 -2 -9 -7 -8 -1 -9 -1 -5 -2 -8 -8 -9 -9 -3 -8 -5 -5 -3 -6 -8 -3 -2 -6 -1 -4 -9 -6 -4 -8 -4 -3 -1 -8 -1 -3 -4 -5 -6 -5 -1 -9 -2 -6 -5 -1 -4 -7 -3 -0 -0 -6 -1 -0 -7 -7 -5 -8 -7 -4 -7 -9 -0 -0 -8 -1 -3 -9 -2 -1 -4 -7 -7 -1 -1 -8 -2 -9 -0 -0 -3 -1 -7 -6 -6 -3 -6 -1 -4 -8 -9 -4 -9 -3 -6 -6 -5 -8 -8 -8 -8 -9 -3 -8 -3 -7 -0 -0 -4 -0 -7 -7 -4 -8 -9 -2 -8 -3 -3 -1 -5 -5 -1 -1 -5 -1 -9 -3 -3 -1 -4 -7 -1 -4 -7 -3 -5 -1 -6 -9 -5 -3 -8 -2 -8 -8 -0 -5 -6 -0 -6 -0 -0 -3 -6 -2 -2 -6 -8 -1 -7 -1 -5 -3 -4 -6 -2 -7 -6 -8 -1 -2 -4 -1 -2 -3 -5 -6 -7 -8 -9 -4 -4 -6 -2 -7 -8 -5 -1 -7 -1 -6 -2 -1 -1 -2 -2 -8 -4 -0 -7 -9 -1 -7 -6 -7 -1 -2 -2 -3 -5 -2 -4 -1 -9 -4 -9 -8 -0 -4 -3 -9 -3 -9 -1 -4 -7 -5 -8 -6 -9 -9 -9 -9 -4 -1 -4 -3 -3 -5 -6 -6 -0 -2 -9 -2 -0 -4 -2 -6 -9 -9 -6 -3 -6 -2 -1 -5 -6 -8 -0 -2 -8 -4 -5 -6 -7 -5 -2 -6 -8 -0 -5 -1 -8 -9 -7 -3 -0 -6 -8 -3 -4 -5 -3 -2 -4 -6 -9 -4 -8 -2 -8 -9 -9 -0 -6 -0 -2 -1 -1 -4 -1 -7 -2 -3 -2 -1 -9 -6 -0 -3 -8 -3 -3 -9 -2 -0 -7 -7 -2 -0 -8 -6 -1 -1 -1 -6 -1 -2 -4 -1 -8 -0 -9 -8 -3 -5 -0 -2 -1 -8 -8 -1 -9 -7 -8 -9 -7 -9 -9 -4 -3 -1 -3 -7 -0 -8 -9 -1 -7 -0 -4 -0 -5 -0 -0 -5 -7 -6 -3 -2 -9 -8 -2 -9 -7 -2 -8 -1 -9 -1 -4 -9 -0 -7 -6 -8 -2 -1 -9 -1 -9 -0 -5 -5 -3 -6 -2 -6 -5 -0 -6 -4 -0 -1 -6 -1 -2 -6 -4 -6 -4 -9 -6 -9 -5 -9 -8 -5 -6 -0 -0 -1 -4 -9 -1 -3 -4 -1 -6 -4 -5 -1 -9 -8 -4 -6 -4 -1 -8 -2 -3 -7 -2 -8 -3 -3 -1 -6 -3 -1 -4 -2 -2 -1 -6 -7 -9 -2 -0 -0 -7 -4 -5 -4 -4 -5 -8 -6 -1 -8 -1 -8 -4 -6 -4 -1 -2 -9 -9 -6 -6 -9 -7 -6 -4 -6 -3 -9 -5 -0 -8 -6 -2 -1 -7 -6 -4 -8 -3 -4 -1 -4 -6 -1 -9 -1 -8 -0 -6 -2 -1 -2 -0 -9 -8 -6 -2 -4 -4 -7 -7 -8 -8 -3 -7 -6 -3 -5 -9 -5 -2 -7 -4 -6 -2 -3 -3 -0 -1 -3 -8 -8 -9 -0 -0 -6 -8 -3 -8 -9 -2 -1 -6 -3 -6 -9 -3 -1 -9 -7 -4 -8 -7 -9 -4 -8 -0 -3 -8 -7 -1 -3 -0 -5 -4 -4 -2 -4 -9 -5 -4 -1 -9 -3 -9 -7 -6 -6 -1 -5 -2 -9 -7 -7 -4 -9 -5 -7 -8 -5 -7 -6 -7 -4 -3 -0 -4 -7 -5 -8 -5 -1 -0 -0 -4 -7 -9 -0 -7 -2 -8 -8 -0 -1 -9 -5 -9 -5 -5 -4 -7 -4 -9 -8 -9 -1 -3 -6 -4 -0 -5 -7 -7 -2 -0 -2 -4 -7 -2 -2 -1 -4 -4 -6 -8 -6 -5 -0 -3 -8 -4 -6 -7 -6 -2 -1 -8 -4 -5 -2 -1 -0 -0 -7 -4 -0 -9 -9 -1 -7 -2 -1 -5 -5 -1 -8 -4 -5 -5 -7 -6 -8 -9 -0 -6 -6 -1 -7 -5 -4 -3 -8 -6 -9 -2 -1 -1 -4 -9 -5 -8 -1 -0 -6 -0 -0 -4 -2 -3 -6 -7 -4 -1 -8 -4 -1 -2 -0 -8 -6 -1 -5 -2 -2 -5 -7 -4 -6 -9 -6 -1 -9 -0 -8 -9 -4 -4 -7 -1 -3 -1 -4 -8 -9 -5 -9 -5 -6 -4 -9 -4 -7 -0 -1 -6 -0 -1 -8 -0 -6 -6 -1 -7 -3 -7 -9 -0 -9 -6 -9 -7 -3 -0 -2 -1 -7 -0 -0 -2 -1 -1 -6 -6 -7 -0 -2 -1 -8 -5 -5 -4 -3 -6 -1 -4 -0 -2 -4 -0 -1 -5 -4 -1 -0 -8 -2 -7 -4 -3 -3 -3 -1 -9 -2 -0 -6 -0 -6 -7 -9 -3 -7 -9 -9 -5 -7 -1 -3 -6 -9 -1 -7 -2 -7 -3 -9 -3 -7 -1 -4 -9 -3 -1 -5 -3 -1 -4 -1 -0 -9 -7 -3 -2 -3 -7 -7 -8 -7 -7 -6 -4 -7 -2 -6 -5 -6 -4 -0 -4 -8 -1 -1 -3 -9 -0 -1 -2 -2 -5 -8 -3 -4 -8 -7 -4 -2 -3 -1 -3 -8 -4 -9 -4 -0 -9 -6 -9 -1 -0 -4 -9 -1 -0 -2 -1 -7 -3 -1 -6 -4 -7 -8 -7 -8 -5 -2 -4 -7 -7 -2 -2 -8 -4 -1 -7 -5 -3 -2 -1 -6 -5 -1 -9 -8 -1 -2 -6 -1 -8 -2 -5 -9 -2 -2 -4 -0 -2 -0 -2 -9 -9 -4 -4 -7 -7 -5 -8 -9 -1 -5 -0 -6 -8 -1 -0 -0 -9 -4 -9 -2 -5 -6 -2 -9 -1 -9 -1 -8 -3 -0 -6 -6 -9 -2 -1 -4 -5 -1 -2 -2 -1 -3 -0 -5 -0 -7 -9 -5 -8 -7 -2 -2 -6 -6 -8 -8 -0 -0 -4 -9 -5 -1 -5 -3 -2 -9 -2 -2 -9 -6 -8 -2 -0 -0 -9 -2 -3 -1 -5 -0 -8 -3 -2 -8 -2 -4 -6 -3 -2 -6 -5 -0 -7 -5 -8 -0 -2 -9 -4 -5 -6 -0 -9 -9 -9 -4 -7 -9 -5 -9 -2 -1 -6 -1 -5 -9 -4 -1 -1 -5 -1 -3 -4 -4 -0 -9 -0 -4 -9 -3 -2 -3 -0 -4 -7 -1 -1 -5 -6 -1 -7 -0 -3 -6 -1 -9 -0 -3 -5 -3 -1 -2 -0 -5 -9 -1 -9 -7 -0 -6 -7 -1 -8 -8 -7 -2 -1 -5 -6 -0 -3 -6 -0 -1 -3 -6 -4 -9 -7 -0 -4 -4 -1 -7 -0 -3 -8 -6 -8 -1 -4 -0 -7 -2 -8 -8 -8 -8 -1 -9 -9 -0 -6 -0 -5 -5 -7 -3 -8 -3 -7 -1 -6 -2 -9 -6 -5 -0 -4 -7 -7 -8 -9 -0 -6 -3 -5 -2 -6 -0 -0 -9 -7 -9 -2 -4 -5 -0 -6 -4 -1 -2 -9 -8 -7 -7 -8 -8 -9 -1 -9 -7 -6 -7 -3 -3 -2 -4 -3 -9 -8 -6 -2 -5 -7 -9 -9 -5 -4 -1 -2 -0 -1 -4 -8 -2 -2 -5 -7 -1 -8 -6 -7 -4 -0 -3 -2 -1 -4 -3 -5 -9 -0 -7 -1 -1 -3 -9 -8 -9 -1 -7 -9 -3 -3 -0 -6 -6 -6 -2 -2 -9 -5 -2 -4 -6 -5 -3 -9 -2 -5 -1 -7 -5 -6 -8 -5 -9 -6 -8 -1 -0 -1 -8 -2 -8 -9 -2 -9 -6 -0 -5 -3 -6 -3 -9 -2 -0 -9 -9 -0 -3 -1 -4 -7 -8 -2 -9 -5 -5 -2 -6 -0 -9 -7 -6 -2 -1 -3 -4 -4 -7 -7 -8 -9 -6 -5 -8 -9 -9 -9 -4 -0 -3 -2 -6 -3 -5 -4 -9 -5 -4 -4 -1 -4 -2 -0 -6 -8 -5 -9 -7 -4 -7 -9 -5 -3 -3 -0 -2 -3 -4 -4 -2 -6 -8 -0 -5 -9 -1 -7 -5 -3 -1 -6 -1 -6 -1 -6 -4 -3 -9 -4 -6 -3 -1 -1 -6 -9 -3 -7 -2 -3 -5 -5 -5 -6 -0 -6 -1 -7 -5 -8 -0 -8 -3 -1 -3 -9 -2 -7 -0 -8 -0 -0 -3 -0 -6 -5 -1 -5 -6 -2 -9 -7 -5 -6 -4 -3 -6 -2 -1 -9 -3 -5 -9 -4 -3 -6 -8 -1 -1 -5 -8 -3 -4 -2 -2 -1 -1 -4 -2 -8 -1 -8 -9 -0 -8 -1 -8 -1 -9 -9 -0 -0 -4 -7 -1 -0 -8 -1 -3 -9 -9 -7 -1 -2 -9 -5 -6 -1 -3 -8 -6 -1 -9 -3 -8 -2 -5 -7 -1 -9 -0 -0 -7 -9 -5 -9 -5 -6 -3 -6 -8 -4 -4 -9 -5 -8 -8 -5 -1 -9 -6 -7 -0 -4 -9 -5 -2 -9 -2 -1 -0 -9 -7 -7 -7 -6 -0 -1 -9 -6 -0 -1 -9 -1 -2 -9 -3 -1 -0 -3 -6 -5 -7 -6 -6 -8 -1 -8 -1 -7 -3 -3 -6 -1 -5 -5 -0 -1 -2 -9 -1 -4 -1 -9 -6 -1 -7 -5 -7 -6 -3 -2 -4 -8 -7 -8 -0 -2 -1 -6 -5 -4 -0 -0 -4 -1 -1 -1 -1 -4 -8 -7 -9 -2 -9 -1 -6 -4 -1 -2 -2 -1 -1 -7 -3 -3 -4 -7 -9 -7 -0 -0 -4 -1 -1 -3 -6 -5 -0 -1 -4 -6 -6 -7 -8 -9 -7 -5 -2 -6 -1 -1 -3 -6 -8 -0 -2 -5 -7 -8 -5 -0 -9 -4 -4 -3 -1 -2 -9 -1 -3 -7 -6 -9 -1 -9 -3 -7 -1 -7 -1 -9 -3 -6 -0 -1 -5 -6 -6 -2 -3 -9 -7 -6 -6 -9 -7 -6 -6 -2 -4 -1 -8 -1 -2 -3 -7 -9 -5 -9 -4 -1 -0 -3 -1 -2 -7 -5 -0 -2 -4 -1 -8 -5 -4 -0 -0 -0 -2 -7 -0 -8 -8 -4 -6 -3 -4 -0 -6 -9 -1 -7 -8 -3 -1 -6 -3 -5 -9 -9 -1 -6 -1 -1 -4 -0 -9 -2 -4 -7 -9 -2 -6 -3 -0 -6 -6 -1 -6 -9 -9 -3 -7 -5 -5 -7 -5 -0 -9 -4 -1 -8 -8 -1 -1 -4 -7 -8 -6 -1 -2 -9 -8 -1 -5 -3 -2 -7 -5 -1 -0 -1 -0 -3 -3 -1 -5 -8 -8 -9 -3 -1 -3 -8 -6 -5 -1 -6 -9 -2 -8 -7 -9 -0 -8 -5 -4 -9 -5 -5 -8 -9 -8 -9 -9 -9 -1 -0 -9 -6 -7 -0 -6 -1 -3 -0 -6 -8 -2 -0 -1 -5 -6 -9 -8 -2 -5 -3 -3 -8 -1 -2 -3 -2 -0 -5 -2 -5 -1 -1 -9 -3 -9 -1 -4 -7 -9 -4 -7 -6 -1 -9 -7 -7 -1 -5 -9 -2 -8 -6 -7 -7 -1 -5 -4 -4 -0 -9 -7 -1 -6 -3 -0 -2 -7 -2 -7 -1 -3 -2 -4 -2 -1 -6 -8 -5 -1 -0 -5 -7 -1 -7 -3 -9 -8 -0 -9 -2 -9 -9 -6 -6 -3 -2 -6 -9 -5 -5 -4 -1 -1 -4 -6 -0 -1 -5 -8 -0 -0 -3 -9 -8 -1 -0 -9 -2 -6 -2 -0 -6 -8 -7 -0 -7 -5 -7 -5 -1 -1 -5 -7 -7 -7 -3 -4 -1 -0 -6 -9 -9 -6 -9 -1 -7 -4 -5 -8 -9 -9 -1 -1 -9 -9 -1 -7 -7 -6 -5 -5 -2 -7 -1 -3 -6 -8 -5 -2 -7 -1 -4 -0 -8 -5 -8 -5 -1 -2 -4 -5 -5 -2 -1 -3 -5 -2 -2 -9 -4 -9 -9 -5 -9 -1 -3 -2 -9 -6 -2 -2 -0 -7 -5 -7 -3 -4 -9 -4 -1 -2 -9 -2 -2 -8 -1 -0 -0 -9 -0 -6 -2 -4 -1 -0 -9 -7 -1 -1 -6 -9 -0 -8 -2 -9 -5 -0 -9 -3 -0 -7 -2 -7 -6 -0 -1 -1 -1 -7 -6 -1 -7 -7 -3 -8 -5 -0 -9 -1 -0 -8 -3 -9 -9 -5 -2 -6 -5 -0 -5 -2 -7 -3 -3 -4 -4 -7 -2 -1 -9 -3 -4 -5 -2 -7 -4 -5 -5 -7 -4 -1 -8 -4 -3 -7 -1 -2 -3 -0 -9 -1 -4 -3 -9 -9 -1 -7 -5 -6 -8 -4 -1 -5 -5 -2 -2 -2 -8 -4 -0 -7 -6 -4 -3 -2 -3 -1 -7 -6 -7 -6 -8 -9 -0 -2 -3 -6 -9 -6 -9 -4 -5 -9 -1 -9 -7 -1 -5 -9 -7 -2 -7 -6 -7 -8 -1 -6 -1 -9 -9 -7 -2 -1 -1 -0 -5 -5 -5 -9 -1 -4 -9 -2 -1 -7 -6 -6 -2 -4 -2 -3 -1 -5 -2 -9 -0 -2 -7 -3 -7 -8 -2 -0 -7 -2 -7 -2 -9 -1 -2 -0 -2 -9 -3 -0 -6 -2 -8 -0 -3 -7 -6 -1 -9 -0 -3 -1 -4 -5 -7 -9 -3 -1 -9 -5 -0 -4 -7 -2 -2 -1 -9 -5 -7 -9 -6 -2 -6 -7 -7 -8 -0 -5 -2 -7 -0 -2 -0 -2 -0 -2 -4 -2 -5 -9 -7 -5 -2 -7 -5 -1 -4 -2 -5 -6 -1 -9 -8 -8 -9 -4 -1 -5 -0 -8 -6 -6 -6 -5 -0 -0 -6 -9 -5 -4 -4 -8 -2 -2 -2 -1 -7 -7 -8 -0 -0 -1 -6 -5 -4 -2 -0 -2 -5 -7 -8 -5 -2 -4 -4 -9 -4 -4 -6 -6 -9 -0 -3 -9 -1 -3 -2 -4 -0 -0 -1 -1 -7 -6 -2 -8 -1 -2 -7 -5 -1 -8 -0 -1 -5 -7 -8 -5 -9 -1 -2 -7 -7 -0 -0 -1 -7 -3 -0 -3 -1 -4 -1 -3 -8 -3 -7 -3 -9 -1 -7 -7 -1 -2 -6 -5 -8 -0 -3 -2 -9 -6 -5 -4 -6 -7 -0 -3 -4 -6 -3 -5 -2 -7 -7 -3 -5 -4 -9 -0 -3 -1 -5 -3 -1 -2 -0 -2 -4 -8 -9 -4 -2 -9 -7 -9 -9 -5 -3 -4 -2 -6 -6 -5 -1 -9 -9 -7 -1 -7 -7 -4 -4 -8 -8 -7 -6 -1 -4 -4 -9 -0 -9 -6 -7 -0 -9 -9 -1 -9 -6 -7 -5 -7 -6 -0 -5 -9 -9 -9 -9 -2 -4 -5 -7 -0 -8 -6 -1 -8 -4 -6 -2 -7 -2 -7 -9 -9 -1 -4 -7 -1 -7 -6 -6 -1 -9 -0 -1 -3 -0 -1 -3 -2 -6 -5 -3 -9 -3 -9 -9 -3 -3 -0 -7 -5 -9 -6 -6 -4 -6 -5 -7 -3 -6 -1 -6 -8 -6 -7 -4 -1 -6 -0 -4 -2 -2 -5 -8 -4 -1 -9 -2 -9 -9 -7 -9 -1 -5 -7 -1 -8 -8 -6 -6 -7 -6 -0 -7 -6 -3 -1 -0 -7 -9 -5 -7 -8 -1 -0 -9 -9 -9 -0 -0 -7 -7 -4 -9 -7 -1 -5 -7 -1 -3 -3 -0 -3 -9 -1 -7 -0 -2 -0 -1 -5 -0 -3 -7 -9 -2 -4 -4 -9 -8 -8 -0 -4 -3 -6 -1 -9 -4 -8 -9 -6 -8 -9 -4 -7 -1 -5 -9 -2 -3 -8 -6 -5 -4 -5 -0 -1 -9 -0 -5 -8 -1 -1 -5 -4 -8 -2 -5 -1 -5 -1 -1 -8 -8 -0 -8 -9 -8 -9 -3 -2 -0 -8 -9 -9 -0 -6 -0 -1 -9 -9 -9 -4 -1 -4 -9 -1 -6 -5 -1 -8 -3 -1 -7 -9 -6 -3 -9 -5 -7 -7 -5 -4 -8 -4 -5 -2 -4 -1 -9 -3 -1 -1 -3 -7 -9 -0 -4 -9 -4 -9 -0 -0 -3 -1 -4 -2 -0 -4 -1 -0 -9 -1 -9 -4 -9 -1 -4 -7 -8 -8 -1 -5 -9 -3 -0 -5 -9 -5 -9 -5 -0 -9 -5 -1 -9 -8 -5 -9 -2 -1 -9 -9 -6 -3 -8 -1 -7 -9 -7 -6 -3 -3 -1 -3 -1 -0 -1 -8 -1 -1 -9 -1 -5 -0 -6 -9 -0 -0 -6 -9 -0 -1 -7 -2 -7 -6 -7 -7 -7 -7 -2 -3 -8 -1 -0 -9 -0 -2 -0 -7 -3 -7 -4 -5 -7 -6 -1 -1 -6 -9 -6 -7 -2 -6 -1 -0 -8 -2 -9 -8 -4 -5 -2 -6 -2 -1 -5 -3 -1 -1 -6 -3 -8 -2 -6 -7 -6 -0 -9 -5 -2 -9 -6 -0 -5 -8 -0 -1 -0 -8 -7 -2 -9 -6 -9 -0 -2 -4 -1 -2 -0 -1 -4 -7 -6 -6 -9 -1 -9 -0 -7 -1 -1 -8 -8 -5 -2 -9 -1 -2 -0 -0 -7 -5 -9 -0 -5 -2 -6 -7 -1 -3 -2 -1 -9 -9 -6 -0 -9 -1 -8 -8 -8 -1 -8 -8 -3 -4 -1 -5 -6 -2 -1 -8 -6 -9 -6 -3 -6 -8 -1 -5 -0 -5 -0 -0 -9 -8 -1 -9 -0 -1 -8 -9 -2 -5 -9 -0 -1 -4 -2 -3 -4 -5 -0 -0 -3 -0 -6 -6 -1 -9 -1 -4 -9 -8 -2 -0 -6 -1 -5 -6 -4 -9 -4 -1 -0 -4 -1 -7 -0 -7 -3 -6 -9 -9 -6 -2 -6 -8 -5 -0 -0 -3 -1 -0 -0 -2 -5 -5 -1 -8 -1 -9 -1 -6 -9 -9 -9 -3 -2 -0 -9 -3 -1 -6 -2 -3 -6 -1 -1 -6 -7 -9 -3 -9 -5 -5 -8 -6 -3 -9 -4 -0 -3 -7 -8 -5 -3 -1 -5 -0 -7 -9 -0 -4 -0 -0 -4 -8 -5 -1 -9 -7 -0 -0 -7 -4 -5 -8 -6 -9 -6 -7 -7 -1 -6 -8 -3 -9 -7 -6 -3 -0 -1 -9 -6 -9 -3 -9 -2 -3 -0 -1 -2 -8 -2 -1 -3 -9 -0 -3 -8 -9 -7 -7 -9 -2 -9 -7 -5 -2 -4 -5 -5 -7 -4 -5 -9 -4 -7 -5 -6 -0 -3 -6 -5 -0 -4 -8 -3 -9 -2 -7 -0 -7 -4 -2 -9 -3 -2 -0 -6 -2 -4 -0 -1 -4 -0 -6 -7 -0 -0 -5 -8 -2 -1 -3 -7 -1 -2 -6 -3 -9 -7 -0 -3 -9 -5 -4 -4 -9 -2 -8 -0 -0 -9 -7 -3 -3 -5 -9 -2 -7 -2 -9 -5 -1 -1 -3 -6 -1 -2 -2 -5 -4 -2 -1 -3 -7 -3 -7 -5 -6 -9 -7 -4 -9 -0 -8 -8 -6 -7 -1 -5 -7 -9 -9 -0 -9 -3 -6 -1 -7 -2 -4 -3 -3 -9 -7 -3 -6 -0 -0 -1 -3 -0 -5 -2 -8 -9 -7 -6 -2 -5 -8 -0 -9 -7 -6 -7 -6 -2 -3 -3 -7 -7 -3 -2 -0 -3 -4 -6 -8 -2 -9 -1 -1 -6 -9 -1 -1 -8 -1 -8 -3 -0 -6 -3 -2 -4 -3 -9 -2 -0 -9 -5 -9 -6 -2 -7 -1 -8 -0 -3 -1 -9 -1 -0 -1 -9 -5 -9 -2 -2 -2 -1 -5 -9 -2 -2 -6 -8 -3 -9 -1 -9 -1 -8 -3 -2 -9 -7 -9 -1 -2 -2 -6 -1 -1 -9 -1 -5 -2 -7 -3 -0 -5 -6 -8 -3 -6 -2 -7 -9 -0 -8 -1 -7 -4 -6 -9 -8 -3 -7 -5 -2 -7 -6 -6 -7 -7 -6 -6 -2 -0 -8 -9 -6 -4 -7 -3 -5 -6 -8 -8 -8 -0 -6 -6 -0 -0 -0 -1 -0 -6 -3 -4 -2 -0 -6 -2 -0 -9 -8 -1 -6 -2 -5 -1 -9 -8 -8 -9 -0 -8 -1 -6 -4 -8 -5 -1 -5 -0 -6 -1 -0 -2 -6 -7 -5 -5 -4 -2 -7 -5 -5 -2 -9 -3 -1 -9 -3 -6 -1 -7 -1 -3 -4 -6 -7 -9 -7 -1 -8 -0 -1 -8 -5 -2 -1 -1 -9 -4 -9 -7 -4 -1 -5 -3 -0 -1 -0 -6 -7 -3 -7 -5 -0 -7 -7 -7 -7 -1 -4 -9 -6 -9 -9 -5 -7 -1 -5 -8 -9 -4 -1 -6 -7 -3 -4 -4 -9 -5 -6 -7 -4 -7 -1 -9 -0 -4 -5 -6 -3 -5 -3 -7 -1 -5 -7 -9 -7 -0 -3 -1 -7 -2 -7 -0 -1 -5 -2 -6 -7 -5 -7 -9 -6 -7 -2 -8 -2 -5 -6 -6 -5 -9 -7 -8 -2 -4 -9 -6 -4 -4 -9 -6 -7 -1 -8 -6 -0 -3 -2 -7 -1 -9 -5 -2 -3 -5 -5 -7 -9 -7 -9 -2 -7 -8 -5 -2 -7 -5 -0 -1 -1 -8 -0 -8 -5 -6 -3 -0 -8 -4 -9 -6 -4 -1 -0 -9 -3 -8 -4 -2 -8 -1 -1 -6 -5 -1 -2 -7 -8 -6 -2 -8 -7 -8 -9 -7 -7 -0 -2 -3 -0 -8 -9 -8 -4 -9 -2 -9 -7 -7 -9 -1 -3 -3 -3 -8 -0 -6 -2 -7 -7 -2 -5 -2 -9 -8 -0 -3 -3 -4 -4 -3 -2 -5 -2 -8 -9 -7 -9 -6 -1 -0 -4 -5 -5 -2 -7 -4 -9 -4 -6 -9 -7 -9 -2 -1 -8 -8 -3 -5 -2 -9 -1 -2 -7 -1 -4 -4 -6 -5 -7 -2 -6 -4 -3 -1 -6 -9 -0 -4 -8 -1 -1 -0 -0 -9 -6 -1 -2 -4 -0 -7 -3 -2 -1 -0 -3 -2 -3 -9 -7 -4 -0 -7 -5 -5 -4 -1 -4 -1 -9 -0 -0 -3 -1 -0 -6 -1 -1 -7 -7 -6 -5 -0 -5 -5 -9 -2 -2 -5 -9 -8 -5 -2 -9 -8 -6 -7 -1 -0 -9 -3 -5 -1 -9 -1 -3 -1 -8 -2 -5 -3 -4 -7 -3 -9 -6 -7 -0 -1 -6 -8 -3 -3 -9 -6 -3 -1 -3 -7 -1 -7 -1 -1 -9 -4 -1 -3 -6 -1 -5 -1 -5 -2 -7 -2 -6 -1 -8 -9 -4 -4 -1 -6 -6 -9 -4 -0 -2 -3 -3 -1 -7 -6 -0 -7 -8 -7 -1 -2 -3 -2 -6 -7 -2 -9 -8 -7 -6 -1 -6 -0 -3 -6 -4 -4 -9 -7 -7 -1 -5 -4 -9 -2 -6 -9 -1 -1 -9 -7 -6 -7 -2 -9 -2 -7 -2 -7 -8 -8 -6 -3 -6 -7 -6 -2 -1 -9 -8 -1 -2 -0 -6 -5 -9 -5 -9 -5 -1 -5 -1 -7 -3 -8 -4 -8 -5 -2 -9 -7 -7 -3 -1 -1 -8 -9 -1 -8 -3 -1 -9 -0 -0 -7 -4 -5 -3 -7 -9 -2 -1 -2 -9 -3 -4 -4 -7 -1 -7 -3 -3 -7 -7 -2 -9 -2 -4 -2 -0 -4 -8 -8 -2 -1 -3 -9 -5 -2 -0 -2 -9 -0 -7 -6 -5 -9 -1 -1 -9 -5 -0 -4 -5 -9 -6 -2 -0 -9 -6 -7 -9 -8 -2 -9 -5 -8 -0 -6 -0 -9 -9 -9 -7 -3 -4 -7 -8 -1 -4 -6 -7 -1 -0 -3 -1 -8 -4 -3 -2 -9 -6 -1 -7 -6 -4 -9 -4 -9 -4 -1 -3 -7 -7 -1 -4 -6 -9 -0 -7 -0 -3 -4 -0 -2 -0 -2 -7 -2 -8 -0 -9 -1 -4 -2 -0 -5 -1 -0 -6 -3 -5 -7 -3 -6 -6 -5 -1 -0 -3 -6 -4 -4 -4 -7 -9 -5 -3 -7 -7 -1 -4 -0 -4 -9 -6 -3 -9 -6 -6 -0 -9 -9 -4 -1 -9 -2 -8 -4 -5 -1 -5 -3 -1 -9 -6 -7 -2 -3 -6 -9 -4 -1 -2 -1 -6 -6 -5 -3 -0 -1 -7 -1 -8 -1 -9 -0 -7 -9 -8 -1 -4 -7 -7 -7 -3 -2 -6 -7 -6 -0 -3 -4 -7 -7 -9 -4 -2 -1 -8 -6 -7 -6 -0 -7 -4 -9 -0 -2 -9 -3 -2 -9 -2 -2 -1 -0 -7 -3 -3 -2 -1 -4 -0 -2 -9 -8 -6 -1 -1 -3 -1 -9 -1 -3 -9 -2 -6 -6 -2 -1 -7 -9 -6 -4 -6 -4 -0 -4 -6 -0 -5 -2 -7 -1 -3 -9 -3 -2 -4 -2 -6 -8 -8 -3 -6 -0 -2 -1 -6 -9 -5 -0 -6 -5 -1 -7 -8 -5 -1 -1 -8 -9 -8 -1 -9 -6 -9 -1 -5 -2 -4 -3 -8 -0 -8 -1 -9 -6 -9 -7 -9 -8 -7 -3 -2 -5 -5 -9 -1 -9 -8 -9 -4 -7 -9 -6 -3 -9 -7 -8 -2 -8 -1 -7 -1 -0 -4 -6 -8 -1 -9 -7 -0 -8 -4 -0 -5 -8 -6 -0 -7 -7 -5 -5 -6 -1 -6 -8 -0 -0 -3 -6 -1 -6 -0 -7 -2 -9 -1 -6 -9 -7 -5 -4 -3 -8 -9 -7 -2 -8 -6 -9 -8 -8 -1 -5 -4 -9 -1 -0 -2 -2 -0 -6 -1 -3 -4 -1 -0 -8 -0 -8 -1 -9 -4 -7 -9 -1 -7 -9 -1 -8 -7 -9 -8 -1 -2 -7 -4 -6 -3 -0 -5 -7 -9 -3 -1 -3 -0 -9 -8 -9 -6 -8 -1 -0 -6 -8 -1 -1 -0 -3 -4 -3 -2 -1 -9 -1 -1 -6 -9 -2 -1 -0 -2 -9 -1 -1 -4 -8 -4 -3 -7 -1 -1 -9 -9 -0 -1 -9 -1 -6 -3 -1 -4 -7 -8 -0 -0 -9 -3 -8 -1 -1 -2 -6 -7 -7 -0 -4 -5 -2 -1 -9 -1 -2 -1 -3 -9 -0 -2 -1 -9 -0 -8 -6 -0 -8 -2 -0 -0 -5 -9 -9 -6 -1 -1 -4 -5 -5 -9 -8 -7 -6 -8 -5 -2 -0 -3 -8 -8 -2 -0 -2 -4 -7 -2 -4 -2 -7 -5 -3 -7 -2 -8 -0 -1 -8 -7 -9 -7 -0 -9 -4 -2 -0 -7 -6 -3 -5 -1 -9 -9 -8 -2 -4 -6 -2 -2 -9 -3 -2 -9 -1 -5 -9 -9 -5 -9 -7 -6 -1 -7 -6 -3 -0 -4 -3 -8 -4 -7 -3 -6 -1 -3 -0 -5 -1 -6 -3 -9 -0 -1 -2 -0 -6 -7 -2 -0 -1 -4 -2 -6 -7 -6 -9 -0 -3 -7 -4 -6 -1 -1 -2 -9 -0 -0 -7 -3 -3 -2 -1 -7 -9 -0 -5 -1 -2 -6 -7 -4 -2 -2 -6 -1 -1 -4 -9 -1 -4 -3 -4 -8 -1 -7 -0 -7 -0 -8 -6 -1 -3 -0 -7 -3 -7 -1 -1 -7 -6 -4 -9 -3 -6 -0 -6 -2 -9 -2 -6 -1 -9 -1 -7 -0 -7 -3 -5 -3 -0 -7 -9 -8 -2 -6 -3 -9 -1 -4 -1 -2 -6 -6 -4 -1 -7 -1 -4 -8 -0 -9 -8 -9 -7 -4 -1 -5 -0 -2 -1 -8 -7 -3 -2 -6 -4 -8 -3 -1 -6 -9 -8 -2 -7 -0 -1 -9 -3 -7 -7 -7 -9 -9 -5 -2 -3 -5 -6 -0 -2 -1 -3 -7 -2 -1 -3 -2 -6 -7 -2 -0 -1 -8 -2 -9 -1 -9 -6 -6 -8 -8 -1 -1 -3 -1 -7 -5 -4 -1 -8 -1 -6 -6 -6 -1 -2 -6 -9 -3 -3 -1 -0 -5 -2 -8 -3 -5 -7 -4 -8 -6 -1 -1 -4 -5 -8 -7 -4 -2 -2 -0 -9 -9 -1 -1 -9 -9 -2 -1 -2 -1 -6 -4 -3 -1 -6 -9 -2 -2 -0 -1 -1 -0 -4 -6 -4 -8 -0 -9 -1 -4 -0 -2 -5 -6 -2 -2 -7 -3 -1 -8 -5 -2 -9 -8 -0 -4 -1 -6 -8 -8 -2 -6 -2 -4 -9 -9 -4 -7 -6 -0 -0 -2 -4 -8 -3 -1 -0 -8 -9 -5 -4 -0 -3 -8 -3 -4 -4 -6 -8 -6 -4 -0 -2 -6 -9 -5 -0 -3 -4 -3 -0 -1 -9 -1 -7 -1 -3 -0 -8 -4 -7 -0 -2 -6 -1 -3 -6 -0 -4 -6 -6 -7 -6 -1 -0 -9 -9 -0 -2 -8 -9 -3 -6 -1 -6 -2 -3 -7 -5 -8 -8 -3 -3 -0 -9 -6 -2 -7 -0 -9 -9 -1 -7 -6 -6 -1 -4 -8 -8 -9 -8 -9 -7 -1 -6 -2 -7 -9 -8 -8 -0 -1 -0 -0 -2 -4 -4 -9 -1 -0 -1 -6 -2 -5 -6 -3 -7 -6 -8 -0 -4 -7 -6 -9 -1 -5 -4 -7 -2 -9 -7 -4 -2 -3 -4 -9 -8 -0 -6 -6 -9 -4 -5 -2 -4 -6 -8 -1 -6 -9 -6 -5 -6 -2 -7 -6 -9 -6 -7 -5 -6 -0 -3 -9 -7 -6 -6 -4 -6 -1 -6 -0 -1 -8 -3 -1 -1 -7 -9 -3 -6 -8 -5 -2 -9 -1 -4 -1 -4 -5 -9 -6 -6 -5 -1 -3 -3 -1 -4 -2 -1 -5 -5 -0 -7 -3 -9 -2 -8 -0 -9 -8 -6 -7 -4 -6 -0 -7 -2 -8 -4 -3 -0 -1 -3 -9 -1 -0 -9 -5 -8 -0 -0 -1 -4 -7 -8 -7 -8 -3 -5 -0 -4 -4 -5 -3 -4 -9 -7 -1 -3 -5 -2 -5 -7 -0 -1 -2 -7 -9 -5 -8 -1 -1 -7 -0 -1 -6 -5 -1 -7 -5 -1 -5 -7 -5 -0 -9 -5 -7 -4 -2 -7 -3 -1 -9 -6 -3 -6 -3 -1 -6 -9 -7 -6 -2 -3 -1 -7 -9 -9 -5 -2 -2 -4 -0 -7 -6 -6 -1 -1 -1 -8 -7 -1 -7 -2 -7 -9 -2 -2 -4 -0 -0 -1 -2 -4 -9 -2 -7 -9 -2 -9 -8 -2 -4 -3 -9 -8 -8 -3 -6 -3 -3 -7 -6 -8 -0 -2 -9 -7 -1 -1 -9 -3 -0 -6 -9 -3 -8 -5 -0 -5 -9 -1 -1 -6 -4 -2 -7 -2 -3 -6 -4 -1 -9 -0 -3 -8 -5 -1 -5 -9 -3 -8 -1 -5 -0 -8 -3 -8 -9 -0 -9 -0 -9 -0 -0 -9 -9 -3 -1 -7 -7 -4 -0 -2 -6 -2 -4 -0 -1 -5 -0 -7 -8 -9 -7 -7 -1 -1 -2 -4 -8 -7 -1 -1 -6 -2 -3 -2 -8 -8 -9 -5 -9 -4 -9 -6 -6 -9 -7 -9 -5 -0 -6 -3 -0 -1 -5 -6 -8 -9 -9 -9 -4 -5 -3 -7 -3 -9 -7 -5 -0 -6 -4 -2 -9 -0 -8 -4 -7 -6 -2 -1 -7 -6 -3 -6 -9 -7 -9 -3 -4 -6 -6 -4 -3 -8 -1 -9 -9 -1 -3 -0 -6 -7 -6 -1 -1 -2 -6 -9 -8 -6 -9 -1 -0 -7 -5 -1 -9 -3 -1 -2 -2 -0 -8 -7 -2 -6 -2 -7 -8 -8 -1 -2 -9 -8 -2 -7 -0 -0 -3 -4 -9 -2 -0 -3 -8 -3 -1 -7 -9 -3 -3 -2 -5 -0 -1 -3 -5 -2 -8 -9 -9 -9 -2 -4 -1 -4 -1 -6 -6 -0 -6 -4 -9 -1 -6 -4 -9 -0 -1 -9 -9 -9 -3 -9 -9 -4 -4 -5 -6 -0 -0 -7 -7 -0 -6 -8 -1 -9 -1 -1 -4 -7 -4 -2 -4 -1 -5 -4 -7 -6 -9 -4 -2 -3 -9 -7 -1 -0 -5 -5 -1 -3 -7 -4 -1 -5 -8 -5 -6 -5 -0 -0 -3 -1 -9 -0 -5 -9 -6 -7 -4 -6 -9 -5 -4 -7 -8 -8 -0 -5 -2 -4 -6 -0 -0 -6 -5 -0 -5 -1 -5 -7 -7 -2 -7 -0 -3 -0 -3 -5 -3 -6 -9 -6 -0 -9 -5 -5 -0 -2 -7 -6 -6 -4 -7 -2 -7 -1 -1 -2 -9 -6 -1 -0 -2 -2 -8 -1 -3 -5 -2 -5 -9 -8 -5 -6 -6 -1 -0 -1 -6 -9 -5 -2 -7 -2 -3 -4 -1 -0 -9 -4 -0 -7 -8 -1 -0 -1 -5 -6 -8 -0 -3 -5 -7 -5 -5 -8 -7 -2 -3 -6 -1 -1 -9 -5 -3 -1 -3 -3 -6 -8 -3 -5 -0 -7 -1 -5 -8 -5 -6 -6 -1 -3 -2 -9 -1 -1 -9 -8 -5 -9 -5 -5 -1 -7 -1 -1 -6 -5 -7 -2 -3 -2 -5 -7 -3 -9 -2 -3 -5 -1 -6 -4 -7 -7 -0 -3 -6 -7 -1 -9 -6 -3 -7 -0 -6 -9 -1 -2 -1 -1 -2 -9 -8 -3 -2 -0 -2 -3 -7 -6 -9 -6 -6 -6 -4 -6 -1 -0 -2 -3 -0 -4 -7 -6 -8 -8 -7 -2 -6 -2 -1 -2 -9 -7 -0 -0 -1 -0 -0 -0 -3 -8 -1 -8 -0 -1 -9 -3 -0 -9 -1 -5 -5 -5 -1 -3 -8 -7 -3 -7 -0 -6 -6 -6 -7 -4 -1 -7 -5 -2 -1 -4 -7 -2 -4 -0 -5 -4 -9 -5 -1 -5 -5 -8 -7 -7 -9 -1 -5 -4 -6 -7 -2 -7 -1 -5 -9 -9 -7 -9 -1 -1 -0 -6 -6 -1 -4 -1 -0 -0 -7 -1 -2 -8 -9 -2 -6 -9 -2 -7 -0 -8 -0 -0 -0 -7 -3 -3 -4 -1 -9 -0 -2 -0 -0 -2 -2 -1 -3 -5 -6 -8 -7 -2 -4 -3 -9 -6 -4 -9 -5 -6 -1 -2 -3 -1 -1 -2 -2 -9 -2 -7 -0 -6 -9 -0 -1 -0 -8 -5 -6 -4 -2 -0 -9 -9 -6 -1 -6 -7 -9 -0 -1 -3 -1 -2 -7 -8 -9 -1 -9 -1 -0 -7 -6 -5 -0 -5 -3 -5 -5 -8 -7 -3 -3 -2 -3 -3 -6 -6 -3 -1 -1 -4 -6 -1 -5 -3 -9 -5 -4 -1 -6 -7 -0 -2 -0 -8 -1 -9 -5 -4 -8 -3 -3 -1 -8 -2 -2 -0 -8 -1 -6 -8 -1 -0 -3 -0 -4 -2 -4 -8 -1 -5 -2 -3 -6 -5 -8 -5 -8 -0 -1 -9 -8 -0 -8 -0 -5 -6 -1 -4 -8 -7 -1 -3 -4 -0 -2 -6 -3 -0 -3 -8 -4 -5 -9 -1 -2 -0 -8 -9 -2 -3 -3 -7 -5 -5 -3 -1 -6 -0 -5 -9 -5 -1 -5 -5 -6 -1 -7 -0 -1 -1 -6 -8 -5 -9 -0 -6 -5 -0 -8 -2 -1 -3 -0 -5 -6 -5 -6 -1 -8 -0 -0 -5 -9 -2 -9 -5 -2 -2 -9 -9 -8 -8 -3 -4 -7 -4 -8 -5 -3 -7 -7 -1 -6 -7 -7 -0 -1 -2 -2 -3 -5 -6 -1 -7 -7 -9 -3 -4 -2 -8 -0 -6 -8 -9 -1 -7 -8 -7 -8 -7 -1 -0 -9 -6 -3 -7 -5 -7 -2 -5 -5 -6 -6 -4 -8 -5 -7 -6 -6 -2 -6 -4 -1 -9 -6 -6 -2 -1 -6 -6 -1 -5 -8 -0 -2 -9 -6 -4 -6 -3 -1 -1 -6 -6 -9 -5 -7 -9 -6 -5 -1 -5 -7 -5 -3 -9 -6 -6 -3 -1 -6 -8 -6 -0 -6 -2 -4 -6 -2 -2 -3 -4 -6 -6 -7 -5 -3 -0 -5 -1 -3 -1 -8 -8 -9 -8 -6 -1 -1 -2 -3 -8 -8 -9 -1 -4 -1 -0 -0 -5 -0 -7 -9 -9 -2 -1 -6 -9 -9 -9 -1 -3 -1 -4 -0 -4 -9 -0 -4 -1 -6 -5 -4 -1 -5 -9 -1 -7 -5 -8 -2 -3 -0 -9 -8 -9 -2 -4 -6 -1 -9 -9 -0 -1 -4 -1 -7 -1 -9 -1 -1 -4 -5 -0 -7 -3 -5 -2 -0 -1 -7 -1 -6 -8 -6 -7 -7 -3 -3 -8 -7 -7 -1 -3 -2 -0 -5 -0 -4 -2 -8 -6 -4 -7 -8 -1 -4 -1 -7 -1 -4 -0 -5 -3 -6 -6 -0 -6 -8 -2 -1 -9 -8 -2 -0 -5 -7 -0 -7 -6 -1 -6 -6 -1 -2 -1 -0 -1 -3 -0 -5 -8 -2 -7 -6 -2 -1 -4 -0 -5 -1 -3 -1 -6 -1 -9 -6 -2 -8 -0 -2 -0 -0 -6 -3 -4 -5 -4 -0 -0 -1 -4 -0 -2 -8 -4 -0 -5 -6 -6 -9 -1 -6 -4 -4 -7 -2 -1 -5 -2 -6 -6 -3 -1 -8 -1 -8 -1 -5 -5 -2 -1 -9 -9 -9 -5 -3 -7 -9 -0 -8 -2 -3 -4 -8 -5 -9 -0 -7 -2 -1 -9 -9 -7 -2 -9 -7 -4 -5 -5 -4 -0 -2 -2 -5 -4 -5 -3 -7 -6 -1 -2 -8 -2 -0 -8 -9 -9 -6 -5 -4 -9 -6 -5 -1 -6 -2 -7 -9 -7 -6 -4 -1 -5 -3 -9 -7 -6 -1 -8 -3 -5 -0 -5 -9 -9 -9 -5 -6 -3 -3 -1 -0 -4 -8 -9 -4 -1 -3 -4 -7 -4 -5 -9 -4 -7 -7 -8 -6 -4 -9 -0 -0 -0 -7 -7 -0 -7 -0 -6 -0 -0 -0 -1 -5 -9 -6 -8 -1 -5 -6 -9 -1 -3 -1 -0 -2 -6 -5 -4 -2 -1 -9 -6 -7 -7 -8 -3 -8 -4 -4 -9 -3 -0 -7 -1 -1 -0 -5 -6 -9 -1 -0 -3 -3 -1 -7 -9 -9 -5 -1 -7 -7 -7 -7 -2 -7 -6 -6 -5 -3 -8 -1 -1 -1 -3 -9 -6 -6 -1 -5 -7 -4 -6 -8 -1 -7 -1 -5 -9 -0 -6 -3 -1 -2 -3 -3 -9 -8 -3 -9 -7 -2 -5 -4 -3 -9 -1 -1 -3 -1 -7 -5 -0 -2 -4 -5 -8 -4 -2 -8 -2 -3 -0 -3 -5 -7 -6 -8 -8 -5 -8 -1 -9 -2 -8 -7 -1 -9 -7 -0 -6 -6 -2 -1 -7 -3 -1 -5 -1 -6 -2 -0 -1 -0 -0 -2 -3 -9 -9 -0 -8 -6 -5 -8 -5 -0 -2 -7 -0 -4 -2 -1 -3 -4 -4 -5 -3 -1 -0 -1 -2 -0 -1 -8 -7 -0 -4 -3 -2 -2 -2 -3 -0 -3 -9 -3 -0 -3 -4 -9 -8 -7 -8 -4 -7 -9 -2 -6 -9 -6 -4 -7 -6 -1 -1 -6 -2 -7 -9 -5 -3 -1 -9 -0 -2 -4 -6 -7 -6 -7 -3 -7 -1 -4 -7 -7 -6 -1 -0 -5 -8 -7 -5 -4 -0 -2 -9 -2 -0 -0 -1 -0 -8 -2 -6 -2 -4 -7 -5 -3 -8 -0 -1 -4 -7 -4 -4 -5 -6 -9 -4 -9 -1 -3 -4 -9 -1 -1 -9 -1 -5 -4 -1 -8 -5 -2 -6 -3 -4 -6 -0 -6 -4 -4 -3 -3 -4 -4 -2 -8 -4 -0 -6 -8 -3 -7 -9 -6 -5 -9 -5 -3 -2 -5 -1 -3 -0 -9 -3 -0 -6 -2 -1 -6 -6 -2 -6 -5 -8 -7 -2 -4 -1 -9 -9 -7 -0 -6 -8 -3 -7 -0 -4 -4 -9 -8 -0 -0 -6 -7 -1 -1 -4 -9 -9 -8 -4 -8 -1 -0 -2 -5 -7 -4 -7 -6 -3 -7 -8 -2 -1 -3 -6 -8 -9 -6 -4 -5 -1 -2 -3 -1 -7 -6 -7 -9 -5 -1 -2 -9 -9 -3 -2 -1 -8 -0 -2 -1 -4 -6 -3 -3 -2 -5 -3 -0 -9 -4 -8 -1 -6 -6 -3 -8 -2 -1 -4 -0 -8 -5 -1 -0 -7 -1 -4 -2 -5 -4 -3 -6 -2 -2 -6 -0 -5 -2 -1 -3 -1 -9 -9 -4 -6 -9 -8 -0 -9 -2 -0 -3 -5 -9 -5 -9 -0 -2 -9 -4 -9 -8 -4 -8 -9 -5 -4 -0 -5 -1 -9 -1 -5 -2 -1 -8 -3 -9 -6 -1 -4 -6 -6 -0 -9 -1 -3 -7 -7 -4 -6 -8 -2 -8 -8 -3 -1 -2 -6 -2 -1 -0 -0 -6 -2 -5 -4 -6 -2 -8 -9 -8 -8 -9 -0 -2 -2 -9 -1 -1 -1 -6 -9 -2 -7 -8 -0 -5 -2 -0 -6 -1 -3 -8 -4 -0 -7 -1 -9 -6 -4 -0 -7 -3 -8 -1 -8 -6 -7 -1 -0 -3 -0 -9 -2 -0 -2 -8 -0 -5 -0 -3 -6 -1 -4 -9 -1 -5 -2 -3 -0 -7 -2 -9 -2 -6 -7 -0 -4 -3 -7 -3 -0 -4 -9 -6 -9 -9 -9 -5 -3 -3 -4 -1 -8 -8 -1 -4 -8 -7 -4 -3 -1 -4 -8 -6 -4 -3 -4 -8 -5 -6 -8 -9 -5 -5 -8 -7 -4 -0 -0 -0 -5 -3 -9 -8 -9 -3 -2 -7 -1 -0 -7 -1 -1 -7 -9 -0 -0 -5 -1 -8 -9 -7 -4 -2 -4 -7 -1 -0 -8 -9 -2 -9 -5 -0 -7 -0 -7 -9 -8 -3 -3 -4 -5 -1 -6 -9 -7 -1 -2 -2 -9 -6 -6 -1 -9 -2 -0 -5 -8 -1 -6 -5 -6 -3 -7 -7 -6 -7 -6 -9 -5 -3 -1 -1 -6 -4 -3 -6 -1 -4 -1 -4 -1 -6 -1 -9 -7 -7 -7 -1 -3 -9 -0 -7 -4 -6 -7 -7 -3 -7 -6 -2 -5 -8 -9 -3 -3 -4 -5 -6 -1 -9 -0 -7 -3 -5 -1 -5 -9 -0 -4 -2 -8 -6 -6 -3 -9 -0 -8 -0 -9 -9 -7 -8 -1 -8 -0 -9 -7 -1 -9 -2 -5 -1 -3 -0 -2 -7 -6 -2 -3 -9 -7 -2 -7 -0 -7 -7 -6 -0 -6 -8 -4 -7 -5 -3 -2 -3 -2 -2 -3 -4 -4 -4 -7 -4 -0 -7 -9 -6 -2 -3 -2 -5 -3 -9 -6 -6 -7 -1 -0 -6 -7 -9 -0 -2 -7 -9 -2 -9 -5 -0 -9 -5 -7 -1 -2 -5 -3 -8 -0 -0 -2 -4 -1 -7 -8 -3 -3 -1 -5 -2 -6 -0 -3 -5 -8 -0 -5 -2 -1 -5 -6 -3 -6 -4 -8 -0 -5 -4 -0 -6 -0 -5 -9 -3 -3 -0 -1 -7 -2 -2 -2 -8 -9 -0 -8 -0 -9 -8 -2 -9 -4 -3 -2 -9 -4 -9 -4 -1 -7 -2 -1 -3 -3 -7 -1 -1 -7 -7 -3 -9 -3 -1 -8 -3 -5 -1 -4 -6 -9 -4 -0 -3 -6 -3 -6 -6 -2 -9 -7 -9 -7 -8 -6 -6 -0 -5 -1 -2 -1 -4 -6 -2 -0 -2 -2 -2 -8 -8 -8 -0 -1 -0 -1 -7 -6 -9 -4 -9 -9 -4 -9 -8 -9 -7 -9 -6 -3 -9 -5 -0 -8 -7 -0 -6 -8 -1 -5 -7 -1 -4 -7 -8 -8 -3 -3 -2 -3 -6 -3 -1 -5 -5 -2 -5 -2 -4 -2 -9 -7 -9 -9 -2 -6 -9 -6 -0 -0 -9 -0 -8 -2 -1 -7 -6 -2 -0 -1 -6 -2 -3 -8 -9 -1 -2 -5 -8 -2 -0 -7 -1 -1 -1 -0 -8 -6 -7 -6 -4 -7 -1 -2 -0 -3 -4 -2 -7 -7 -1 -3 -4 -1 -3 -1 -3 -6 -6 -9 -5 -2 -8 -5 -5 -3 -6 -9 -6 -2 -0 -2 -7 -1 -9 -8 -2 -4 -6 -6 -3 -6 -8 -2 -9 -6 -1 -8 -4 -3 -6 -6 -1 -1 -0 -2 -1 -3 -9 -9 -4 -3 -9 -2 -7 -2 -3 -2 -0 -3 -3 -9 -0 -4 -0 -6 -9 -5 -3 -4 -4 -5 -0 -1 -5 -9 -4 -3 -3 -4 -0 -1 -0 -5 -8 -4 -0 -3 -5 -8 -6 -9 -4 -4 -7 -9 -3 -5 -0 -9 -2 -3 -6 -9 -8 -2 -5 -8 -7 -0 -2 -2 -5 -6 -7 -2 -2 -2 -1 -8 -5 -7 -2 -2 -7 -3 -7 -7 -6 -6 -9 -4 -1 -5 -8 -9 -0 -8 -8 -2 -3 -6 -2 -9 -8 -0 -1 -0 -5 -4 -5 -7 -0 -6 -6 -2 -5 -2 -2 -6 -2 -4 -0 -7 -6 -2 -1 -2 -6 -4 -4 -5 -2 -6 -9 -9 -6 -2 -4 -9 -8 -2 -4 -9 -6 -0 -1 -1 -0 -9 -8 -6 -4 -3 -7 -4 -7 -2 -1 -9 -1 -8 -3 -0 -4 -8 -0 -9 -0 -0 -3 -2 -7 -1 -4 -2 -8 -4 -5 -8 -5 -5 -1 -0 -3 -2 -4 -5 -2 -7 -9 -9 -1 -4 -2 -3 -9 -9 -2 -9 -1 -6 -6 -9 -6 -1 -9 -0 -9 -9 -3 -9 -6 -9 -9 -0 -7 -0 -0 -2 -8 -9 -1 -1 -3 -7 -0 -6 -7 -7 -0 -0 -6 -0 -3 -7 -5 -0 -6 -1 -2 -6 -3 -9 -1 -7 -8 -0 -9 -3 -8 -0 -1 -0 -7 -3 -0 -6 -2 -8 -2 -5 -4 -9 -6 -3 -4 -3 -9 -7 -1 -3 -2 -6 -2 -5 -5 -2 -0 -6 -8 -6 -7 -0 -8 -9 -4 -0 -2 -1 -5 -1 -6 -8 -1 -0 -2 -5 -2 -9 -8 -5 -3 -6 -9 -7 -2 -1 -9 -3 -5 -4 -4 -8 -0 -9 -5 -0 -2 -6 -0 -2 -6 -3 -3 -6 -2 -8 -1 -2 -6 -9 -1 -2 -5 -5 -9 -0 -0 -1 -8 -2 -0 -7 -0 -9 -2 -0 -4 -9 -0 -6 -0 -3 -1 -5 -2 -2 -6 -2 -7 -6 -0 -0 -5 -1 -6 -3 -7 -8 -1 -1 -5 -2 -0 -6 -5 -5 -5 -3 -7 -7 -1 -5 -8 -1 -8 -3 -3 -6 -8 -6 -0 -7 -8 -6 -2 -5 -1 -5 -0 -9 -8 -0 -7 -5 -8 -2 -0 -0 -5 -2 -2 -8 -3 -1 -3 -5 -8 -1 -0 -6 -8 -3 -1 -6 -0 -0 -2 -1 -8 -2 -6 -9 -6 -5 -7 -4 -3 -7 -2 -1 -9 -9 -0 -0 -3 -6 -2 -6 -9 -2 -1 -4 -3 -0 -5 -1 -8 -7 -8 -7 -1 -3 -5 -1 -1 -4 -2 -3 -4 -9 -2 -0 -1 -5 -3 -1 -9 -0 -6 -0 -7 -1 -7 -1 -2 -7 -4 -0 -9 -6 -2 -6 -3 -2 -6 -7 -5 -1 -0 -4 -3 -3 -0 -1 -4 -3 -1 -3 -5 -5 -7 -6 -9 -6 -7 -5 -6 -9 -8 -5 -1 -3 -0 -6 -7 -8 -7 -6 -7 -4 -2 -6 -3 -7 -3 -6 -1 -1 -2 -7 -8 -7 -9 -4 -1 -9 -8 -7 -3 -8 -8 -5 -0 -2 -7 -8 -9 -9 -7 -7 -2 -3 -1 -9 -8 -6 -9 -0 -4 -6 -1 -5 -3 -3 -3 -0 -1 -8 -1 -4 -6 -8 -7 -6 -8 -0 -5 -3 -4 -6 -3 -0 -2 -9 -4 -9 -1 -5 -1 -0 -7 -4 -4 -1 -8 -4 -5 -5 -9 -9 -2 -2 -2 -4 -4 -9 -6 -2 -5 -2 -2 -0 -2 -7 -9 -5 -0 -7 -0 -8 -0 -1 -7 -8 -2 -9 -4 -0 -8 -9 -4 -5 -3 -5 -0 -3 -3 -8 -0 -7 -0 -6 -7 -2 -0 -3 -6 -2 -1 -8 -6 -0 -1 -3 -8 -0 -3 -6 -3 -9 -1 -1 -2 -6 -8 -8 -9 -4 -9 -5 -9 -9 -6 -6 -4 -9 -0 -4 -0 -1 -3 -0 -0 -1 -9 -7 -2 -1 -6 -7 -2 -2 -1 -8 -1 -8 -9 -6 -2 -9 -9 -7 -4 -0 -9 -6 -8 -9 -9 -9 -7 -9 -5 -4 -7 -0 -9 -6 -4 -9 -4 -0 -7 -7 -9 -0 -0 -5 -6 -7 -2 -1 -3 -3 -8 -0 -1 -3 -8 -4 -3 -1 -2 -9 -9 -4 -5 -1 -4 -0 -3 -8 -8 -7 -1 -1 -6 -8 -2 -8 -6 -3 -9 -5 -9 -7 -2 -3 -1 -2 -0 -6 -3 -1 -9 -5 -2 -7 -3 -0 -1 -1 -9 -5 -2 -2 -6 -0 -6 -5 -8 -4 -3 -3 -0 -2 -9 -5 -7 -4 -7 -2 -5 -9 -5 -4 -7 -8 -2 -3 -2 -3 -6 -9 -2 -6 -3 -4 -1 -6 -1 -9 -0 -0 -6 -2 -9 -0 -9 -7 -8 -0 -8 -6 -2 -3 -5 -0 -5 -4 -2 -6 -0 -9 -8 -5 -9 -6 -1 -9 -3 -7 -1 -3 -7 -4 -1 -1 -9 -6 -9 -5 -8 -0 -2 -5 -3 -8 -0 -1 -4 -1 -6 -6 -9 -5 -8 -0 -7 -3 -4 -9 -2 -9 -9 -3 -1 -0 -8 -5 -3 -2 -4 -5 -2 -1 -3 -9 -8 -4 -4 -7 -9 -3 -7 -0 -7 -7 -9 -9 -8 -7 -1 -2 -0 -0 -0 -7 -6 -6 -8 -0 -1 -3 -0 -2 -6 -3 -6 -8 -0 -5 -6 -2 -0 -2 -9 -5 -0 -2 -4 -3 -9 -9 -1 -9 -5 -4 -4 -2 -0 -1 -7 -6 -6 -7 -0 -6 -4 -9 -8 -8 -9 -3 -3 -1 -0 -4 -4 -7 -0 -5 -7 -6 -7 -8 -1 -3 -4 -6 -7 -0 -4 -3 -2 -6 -3 -7 -3 -7 -1 -9 -1 -3 -9 -0 -1 -7 -9 -8 -4 -3 -5 -4 -0 -7 -2 -2 -6 -9 -5 -3 -9 -9 -8 -1 -6 -1 -7 -8 -3 -1 -1 -2 -8 -4 -5 -6 -1 -7 -0 -0 -1 -8 -7 -4 -9 -9 -7 -0 -5 -1 -5 -8 -6 -8 -5 -6 -2 -6 -1 -1 -9 -6 -4 -3 -5 -1 -8 -5 -7 -9 -7 -2 -7 -1 -5 -9 -1 -3 -9 -5 -0 -4 -6 -3 -5 -3 -3 -6 -1 -0 -2 -3 -2 -2 -6 -2 -0 -1 -2 -7 -8 -5 -6 -2 -8 -4 -6 -8 -5 -8 -6 -9 -8 -7 -1 -6 -7 -3 -7 -7 -4 -0 -1 -3 -9 -2 -0 -0 -5 -4 -7 -1 -6 -9 -7 -8 -4 -3 -3 -1 -3 -1 -5 -6 -0 -3 -5 -0 -8 -7 -7 -8 -6 -3 -6 -9 -5 -9 -2 -1 -2 -3 -5 -2 -2 -1 -1 -3 -3 -5 -8 -7 -9 -3 -4 -2 -7 -1 -7 -8 -2 -2 -3 -9 -5 -5 -7 -7 -3 -9 -0 -5 -9 -6 -6 -9 -2 -6 -3 -9 -2 -0 -7 -0 -7 -7 -1 -2 -0 -3 -2 -9 -0 -3 -3 -6 -3 -0 -5 -2 -6 -6 -7 -8 -0 -1 -5 -7 -1 -2 -9 -2 -5 -3 -6 -3 -6 -1 -0 -4 -5 -1 -9 -4 -6 -0 -5 -8 -4 -0 -4 -5 -3 -1 -5 -1 -5 -5 -2 -1 -0 -9 -6 -7 -5 -9 -9 -3 -4 -7 -7 -5 -6 -3 -2 -0 -4 -4 -0 -8 -5 -9 -1 -5 -5 -5 -7 -8 -1 -0 -7 -0 -4 -4 -1 -5 -6 -4 -2 -8 -2 -6 -8 -1 -2 -3 -8 -9 -1 -3 -9 -9 -6 -7 -1 -2 -7 -7 -3 -3 -1 -1 -9 -7 -2 -1 -8 -9 -2 -7 -8 -4 -0 -4 -3 -5 -8 -9 -3 -3 -2 -9 -0 -7 -7 -1 -9 -0 -4 -2 -2 -8 -9 -4 -3 -9 -4 -6 -3 -6 -0 -5 -1 -3 -0 -1 -2 -5 -0 -7 -1 -7 -2 -7 -8 -7 -4 -9 -1 -5 -0 -8 -2 -9 -2 -1 -0 -1 -2 -6 -9 -2 -5 -3 -5 -3 -4 -9 -1 -4 -7 -1 -8 -1 -8 -8 -9 -4 -6 -1 -9 -9 -3 -4 -1 -2 -4 -3 -5 -9 -0 -7 -2 -8 -2 -9 -9 -9 -9 -0 -7 -1 -2 -3 -3 -1 -9 -9 -8 -8 -3 -5 -1 -2 -1 -7 -2 -0 -7 -2 -1 -1 -7 -0 -6 -4 -0 -8 -1 -8 -7 -2 -4 -7 -3 -0 -9 -6 -7 -5 -9 -7 -4 -5 -2 -9 -6 -7 -1 -3 -7 -0 -3 -1 -4 -7 -5 -2 -0 -4 -4 -9 -7 -4 -9 -0 -1 -0 -2 -1 -6 -6 -3 -6 -4 -9 -2 -2 -3 -1 -1 -0 -7 -1 -2 -7 -9 -0 -9 -0 -6 -7 -1 -0 -9 -7 -5 -0 -8 -4 -8 -5 -0 -0 -0 -3 -6 -5 -0 -8 -2 -7 -6 -0 -8 -5 -0 -2 -6 -9 -4 -2 -0 -9 -3 -8 -1 -3 -6 -7 -6 -7 -0 -3 -1 -9 -2 -1 -9 -7 -3 -0 -6 -4 -2 -2 -5 -3 -7 -8 -8 -5 -7 -4 -2 -7 -4 -9 -0 -5 -9 -9 -9 -2 -8 -8 -8 -0 -3 -1 -1 -1 -0 -9 -0 -4 -1 -7 -4 -7 -6 -1 -1 -4 -3 -7 -1 -4 -6 -9 -5 -8 -9 -3 -2 -9 -1 -5 -3 -9 -6 -3 -6 -7 -9 -1 -7 -3 -2 -5 -6 -9 -7 -2 -6 -2 -8 -6 -5 -7 -7 -3 -5 -9 -0 -0 -4 -2 -2 -5 -1 -9 -5 -9 -6 -8 -0 -8 -5 -3 -7 -6 -1 -9 -3 -5 -8 -0 -9 -4 -0 -7 -5 -6 -1 -4 -6 -5 -0 -4 -9 -7 -1 -9 -6 -6 -6 -1 -4 -8 -1 -7 -2 -4 -9 -7 -5 -0 -0 -0 -8 -0 -7 -7 -0 -2 -6 -9 -0 -9 -8 -7 -2 -9 -7 -3 -9 -3 -9 -9 -0 -7 -5 -2 -4 -5 -8 -7 -8 -9 -1 -2 -2 -7 -7 -4 -7 -0 -6 -5 -9 -7 -2 -0 -0 -1 -2 -9 -1 -3 -4 -0 -6 -4 -9 -5 -3 -0 -2 -0 -1 -6 -5 -8 -0 -5 -7 -6 -4 -7 -0 -2 -4 -2 -1 -9 -3 -9 -0 -1 -0 -5 -7 -6 -5 -0 -5 -6 -1 -0 -0 -0 -9 -0 -3 -1 -7 -3 -7 -9 -8 -4 -4 -8 -3 -3 -0 -6 -4 -1 -0 -0 -2 -2 -2 -1 -1 -7 -3 -7 -6 -8 -6 -3 -4 -6 -4 -9 -3 -3 -9 -2 -0 -1 -3 -2 -5 -1 -2 -4 -0 -3 -6 -2 -2 -1 -6 -9 -0 -6 -1 -2 -4 -1 -3 -9 -7 -6 -0 -4 -5 -3 -3 -7 -2 -3 -4 -4 -8 -4 -6 -2 -1 -7 -0 -5 -8 -1 -2 -8 -3 -5 -1 -6 -9 -0 -9 -4 -9 -1 -0 -7 -0 -9 -3 -7 -5 -6 -9 -9 -9 -6 -4 -8 -9 -7 -9 -7 -5 -7 -1 -2 -6 -7 -6 -0 -9 -7 -5 -9 -7 -1 -2 -6 -0 -5 -6 -6 -1 -0 -0 -0 -4 -9 -8 -9 -6 -8 -0 -2 -8 -4 -9 -7 -4 -1 -1 -7 -6 -1 -5 -7 -6 -2 -2 -3 -0 -7 -9 -0 -7 -2 -6 -0 -3 -6 -1 -2 -3 -3 -1 -9 -0 -5 -6 -2 -3 -6 -1 -4 -0 -0 -4 -6 -9 -8 -7 -4 -8 -4 -3 -9 -7 -8 -9 -8 -3 -6 -7 -3 -0 -1 -2 -3 -8 -2 -0 -8 -0 -5 -4 -2 -9 -9 -4 -0 -7 -3 -2 -2 -9 -4 -5 -1 -0 -5 -9 -6 -1 -5 -0 -7 -6 -4 -2 -5 -3 -7 -9 -3 -9 -1 -8 -1 -6 -8 -3 -4 -9 -0 -9 -1 -9 -4 -9 -6 -2 -6 -0 -0 -6 -0 -8 -7 -8 -9 -9 -0 -7 -7 -4 -2 -6 -0 -2 -6 -9 -5 -2 -1 -1 -1 -0 -1 -0 -8 -0 -6 -6 -4 -2 -8 -1 -9 -3 -9 -7 -1 -5 -4 -6 -2 -1 -7 -6 -8 -0 -7 -7 -0 -7 -2 -6 -9 -3 -6 -7 -6 -5 -9 -2 -9 -4 -4 -1 -0 -1 -4 -5 -4 -4 -6 -8 -5 -2 -3 -6 -2 -8 -5 -3 -3 -0 -2 -3 -3 -3 -9 -0 -3 -0 -3 -0 -3 -2 -9 -7 -5 -4 -9 -2 -4 -0 -1 -0 -6 -5 -0 -2 -8 -1 -3 -5 -5 -8 -9 -2 -7 -1 -6 -6 -6 -1 -4 -0 -4 -9 -6 -1 -8 -0 -9 -4 -5 -1 -6 -1 -1 -0 -9 -5 -9 -7 -9 -1 -6 -0 -0 -1 -7 -5 -8 -9 -7 -9 -9 -4 -6 -7 -7 -3 -6 -8 -0 -2 -0 -9 -1 -6 -6 -9 -6 -1 -8 -8 -1 -2 -8 -6 -1 -9 -7 -5 -2 -6 -0 -1 -7 -7 -5 -7 -3 -1 -6 -1 -0 -2 -5 -4 -2 -7 -3 -7 -3 -6 -4 -9 -5 -3 -1 -4 -6 -3 -9 -7 -8 -1 -9 -3 -1 -0 -5 -8 -5 -7 -8 -4 -1 -5 -4 -7 -5 -8 -3 -2 -1 -9 -2 -2 -5 -6 -1 -4 -8 -1 -1 -8 -1 -4 -9 -8 -3 -6 -8 -1 -5 -3 -7 -2 -4 -2 -5 -0 -4 -2 -1 -8 -4 -5 -4 -1 -6 -5 -5 -8 -2 -2 -9 -0 -7 -3 -8 -2 -8 -1 -4 -7 -4 -6 -7 -4 -4 -1 -5 -7 -9 -2 -6 -1 -0 -7 -1 -0 -9 -3 -7 -6 -7 -2 -1 -6 -7 -4 -9 -1 -7 -8 -5 -6 -7 -6 -6 -9 -7 -3 -9 -6 -0 -0 -6 -9 -2 -1 -4 -6 -3 -0 -9 -9 -6 -4 -7 -6 -0 -2 -9 -0 -1 -1 -0 -5 -9 -1 -1 -9 -2 -2 -4 -1 -0 -8 -3 -1 -5 -7 -2 -9 -8 -8 -0 -7 -9 -9 -2 -4 -1 -6 -9 -4 -4 -3 -6 -1 -3 -2 -3 -7 -5 -4 -3 -4 -2 -0 -7 -1 -6 -8 -1 -2 -1 -3 -0 -1 -0 -9 -9 -4 -5 -5 -2 -1 -8 -3 -8 -7 -8 -4 -2 -0 -6 -4 -5 -3 -2 -8 -0 -2 -7 -5 -7 -8 -5 -7 -6 -6 -3 -8 -5 -7 -1 -9 -6 -0 -5 -0 -7 -7 -9 -7 -8 -5 -5 -2 -1 -8 -9 -1 -7 -3 -5 -0 -0 -9 -6 -2 -6 -6 -2 -4 -9 -8 -6 -6 -2 -5 -8 -9 -5 -6 -2 -7 -1 -7 -8 -5 -3 -1 -3 -5 -9 -6 -4 -9 -1 -8 -0 -8 -6 -7 -9 -7 -2 -1 -7 -6 -3 -1 -7 -4 -0 -8 -3 -9 -1 -2 -9 -5 -1 -0 -7 -6 -7 -8 -4 -5 -3 -0 -8 -2 -8 -0 -5 -0 -5 -0 -1 -9 -2 -3 -7 -3 -9 -9 -3 -9 -1 -0 -2 -9 -3 -3 -2 -6 -6 -8 -7 -7 -0 -9 -1 -7 -3 -3 -7 -5 -5 -0 -4 -9 -8 -2 -1 -9 -3 -3 -4 -2 -4 -3 -9 -1 -4 -0 -2 -7 -5 -3 -1 -6 -1 -5 -4 -8 -7 -4 -2 -5 -1 -7 -9 -8 -0 -5 -7 -4 -8 -2 -5 -9 -3 -4 -5 -6 -7 -5 -9 -8 -3 -7 -7 -3 -2 -8 -8 -2 -0 -1 -2 -0 -4 -1 -9 -0 -1 -4 -3 -1 -9 -4 -4 -5 -4 -5 -8 -0 -5 -0 -0 -9 -3 -2 -5 -9 -7 -4 -8 -7 -8 -0 -9 -6 -3 -3 -0 -7 -6 -6 -8 -8 -2 -1 -4 -9 -6 -4 -7 -5 -0 -4 -2 -9 -8 -8 -6 -6 -8 -3 -2 -0 -9 -1 -5 -3 -1 -0 -4 -9 -5 -9 -6 -3 -0 -9 -6 -7 -2 -7 -3 -0 -3 -3 -1 -8 -7 -2 -8 -7 -1 -0 -0 -6 -2 -0 -1 -0 -5 -9 -2 -5 -9 -9 -4 -0 -4 -0 -8 -4 -3 -1 -6 -4 -4 -1 -0 -9 -8 -8 -1 -1 -9 -8 -6 -4 -1 -8 -8 -1 -5 -1 -6 -3 -3 -5 -5 -4 -1 -2 -3 -6 -9 -8 -6 -1 -3 -4 -7 -9 -1 -5 -7 -3 -0 -6 -3 -4 -8 -8 -8 -6 -1 -0 -8 -8 -3 -2 -1 -6 -9 -8 -9 -0 -9 -1 -5 -9 -2 -6 -2 -2 -2 -5 -1 -9 -4 -0 -1 -1 -3 -4 -0 -6 -9 -8 -1 -7 -6 -4 -0 -6 -3 -0 -2 -5 -1 -5 -4 -4 -7 -1 -1 -0 -7 -7 -0 -4 -9 -7 -6 -5 -9 -1 -9 -6 -7 -9 -9 -2 -1 -2 -6 -0 -5 -1 -3 -1 -7 -2 -3 -5 -4 -1 -9 -3 -6 -0 -3 -3 -5 -0 -4 -8 -0 -3 -6 -0 -1 -9 -3 -1 -1 -0 -4 -5 -2 -2 -1 -6 -7 -6 -1 -9 -7 -9 -7 -3 -9 -2 diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..c5fff6c --- /dev/null +++ b/pom.xml @@ -0,0 +1,35 @@ + + + 4.0.0 + + + + javacnn + javacnn + 0.5-SNAPSHOT + + Implementation of a CNN in Java + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.7.0 + + 1.8 + 1.8 + -deprecation + UTF-8 + + + + + + + + diff --git a/readme-cn.md b/readme-cn.md deleted file mode 100644 index 49fb496..0000000 --- a/readme-cn.md +++ /dev/null @@ -1,25 +0,0 @@ -# JavaCNN -涓涓嵎绉缁忕綉缁滅殑java瀹炵幇. 浠縈atlab toolbox(https://github.com/rasmusbergpalm/DeepLearnToolbox )瀹炵幇鐨勶紝鍚屾椂杩涜浜嗛儴鍒嗘敼杩涳紝浣垮緱鍗风Н鏍稿拰閲囨牱鍧楀彲浠ヤ负鐭╁舰鑰屼笉浠呬粎鏄鏂瑰舰銆傛洿澶氱粏鑺傦紝璇锋煡鐪媓ttp://www.cnblogs.com/fengfenggirl/p/cnn_implement.html -## 鍒涘缓涓涓嵎绉缁忕綉缁 - - LayerBuilder builder = new LayerBuilder(); - builder.addLayer(Layer.buildInputLayer(new Size(28, 28))); - builder.addLayer(Layer.buildConvLayer(6, new Size(5, 5))); - builder.addLayer(Layer.buildSampLayer(new Size(2, 2))); - builder.addLayer(Layer.buildConvLayer(12, new Size(5, 5))); - builder.addLayer(Layer.buildSampLayer(new Size(2, 2))); - builder.addLayer(Layer.buildOutputLayer(10)); - CNN cnn = new CNN(builder, 50); - -## 鍦 MNIST 鏁版嵁闆嗕笂娴嬭瘯 - - String fileName = "data/train.format"; - Dataset dataset = Dataset.load(fileName, ",", 784); - cnn.train(dataset, 100); - Dataset testset = Dataset.load("data/test.format", ",", -1); - cnn.predict(testset, "data/test.predict"); - -杩唬100娆★紝鍥涙牳CPU澶х害闇瑕佽繍琛屼竴涓皬鏃跺悗锛屾纭巼97.8% - -##Lisence - MIT \ No newline at end of file diff --git a/readme.md b/readme.md index 329ada9..6520b53 100644 --- a/readme.md +++ b/readme.md @@ -1,5 +1,40 @@ # JavaCNN -A Java implement of Convolutional Neural Network. Learn from DeepLearnToolbox(https://github.com/rasmusbergpalm/DeepLearnToolbox) more detail. see here(http://www.cnblogs.com/fengfenggirl/p/cnn_implement.html) + +A Java implementation of Convolutional Neural Network. +This is a mavenized fork of https://github.com/BigPeng/JavaCNN refactored for the intention to use it in productive environments. + +Original ideas are take from the DeepLearnToolbox (https://github.com/rasmusbergpalm/DeepLearnToolbox). + + +## Include in your project + +If you use maven, it's simple: Just add the dependency + + + + + javacnn + javacnn + 0.4 + + + + +and ratopi's repository + + + + ratopi.de releases + http://ratopi.github.io/maven/releases/ + + false + + + + +to your project's pom.xml. + + ## Build a CNN LayerBuilder builder = new LayerBuilder(); @@ -10,16 +45,20 @@ A Java implement of Convolutional Neural Network. Learn from DeepLearnToolbox(ht builder.addLayer(Layer.buildSampLayer(new Size(2, 2))); builder.addLayer(Layer.buildOutputLayer(10)); CNN cnn = new CNN(builder, 50); - + + ## Run on MNIST dataset - - String fileName = "data/train.format"; - Dataset dataset = Dataset.load(fileName, ",", 784); - cnn.train(dataset, 100); - Dataset testset = Dataset.load("data/test.format", ",", -1); - cnn.predict(testset, "data/test.predict"); -It takes a about an hour to complete 100 iteration and get a precison of 97.8% +For running on MNIST dataset see project https://github.com/ratopi/javacnn.mnist. + + +## Source Code + +Get the source code from github: + + git clone https://github.com/ratopi/JavaCNN.git + + +## License -##Lisence - MIT \ No newline at end of file +MIT diff --git a/src/edu/hitsz/c102c/cnn/CNN.java b/src/edu/hitsz/c102c/cnn/CNN.java deleted file mode 100644 index 096ba73..0000000 --- a/src/edu/hitsz/c102c/cnn/CNN.java +++ /dev/null @@ -1,737 +0,0 @@ -package edu.hitsz.c102c.cnn; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.PrintWriter; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; - -import edu.hitsz.c102c.cnn.Layer.Size; -import edu.hitsz.c102c.dataset.Dataset; -import edu.hitsz.c102c.dataset.Dataset.Record; -import edu.hitsz.c102c.util.ConcurenceRunner.TaskManager; -import edu.hitsz.c102c.util.Log; -import edu.hitsz.c102c.util.Util; -import edu.hitsz.c102c.util.Util.Operator; - -public class CNN implements Serializable { - /** - * - */ - private static final long serialVersionUID = 337920299147929932L; - private static double ALPHA = 0.85; - protected static final double LAMBDA = 0; - // 网络的各层 - private List layers; - // 层数 - private int layerNum; - - // 批量更新的大小 - private int batchSize; - // 除数操作符,对矩阵的每一个元素除以一个值 - private Operator divide_batchSize; - - // 乘数操作符,对矩阵的每一个元素乘以alpha值 - private Operator multiply_alpha; - - // 乘数操作符,对矩阵的每一个元素乘以1-labmda*alpha值 - private Operator multiply_lambda; - - /** - * 初始化网络 - * - * @param layerBuilder - * 网络层 - * @param inputMapSize - * 输入map的大小 - * @param classNum - * 类别的个数,要求数据集将类标转化为0-classNum-1的数值 - */ - public CNN(LayerBuilder layerBuilder, final int batchSize) { - layers = layerBuilder.mLayers; - layerNum = layers.size(); - this.batchSize = batchSize; - setup(batchSize); - initPerator(); - } - - /** - * 初始化操作符 - */ - private void initPerator() { - divide_batchSize = new Operator() { - - private static final long serialVersionUID = 7424011281732651055L; - - @Override - public double process(double value) { - return value / batchSize; - } - - }; - multiply_alpha = new Operator() { - - private static final long serialVersionUID = 5761368499808006552L; - - @Override - public double process(double value) { - - return value * ALPHA; - } - - }; - multiply_lambda = new Operator() { - - private static final long serialVersionUID = 4499087728362870577L; - - @Override - public double process(double value) { - - return value * (1 - LAMBDA * ALPHA); - } - - }; - } - - /** - * 在训练集上训练网络 - * - * @param trainset - * @param repeat - * 迭代的次数 - */ - public void train(Dataset trainset, int repeat) { - // 监听停止按钮 - new Lisenter().start(); - for (int t = 0; t < repeat && !stopTrain.get(); t++) { - int epochsNum = trainset.size() / batchSize; - if (trainset.size() % batchSize != 0) - epochsNum++;// 多抽取一次,即向上取整 - Log.i(""); - Log.i(t + "th iter epochsNum:" + epochsNum); - int right = 0; - int count = 0; - for (int i = 0; i < epochsNum; i++) { - int[] randPerm = Util.randomPerm(trainset.size(), batchSize); - Layer.prepareForNewBatch(); - - for (int index : randPerm) { - boolean isRight = train(trainset.getRecord(index)); - if (isRight) - right++; - count++; - Layer.prepareForNewRecord(); - } - - // 跑完一个batch后更新权重 - updateParas(); - if (i % 50 == 0) { - System.out.print(".."); - if (i + 50 > epochsNum) - System.out.println(); - } - } - double p = 1.0 * right / count; - if (t % 10 == 1 && p > 0.96) {//动态调整准学习速率 - ALPHA = 0.001 + ALPHA * 0.9; - Log.i("Set alpha = " + ALPHA); - } - Log.i("precision " + right + "/" + count + "=" + p); - } - } - - private static AtomicBoolean stopTrain; - - static class Lisenter extends Thread { - Lisenter() { - setDaemon(true); - stopTrain = new AtomicBoolean(false); - } - - @Override - public void run() { - System.out.println("Input & to stop train."); - while (true) { - try { - int a = System.in.read(); - if (a == '&') { - stopTrain.compareAndSet(false, true); - break; - } - } catch (IOException e) { - e.printStackTrace(); - } - } - System.out.println("Lisenter stop"); - } - - } - - /** - * 测试数据 - * - * @param trainset - * @return - */ - public double test(Dataset trainset) { - Layer.prepareForNewBatch(); - Iterator iter = trainset.iter(); - int right = 0; - while (iter.hasNext()) { - Record record = iter.next(); - forward(record); - Layer outputLayer = layers.get(layerNum - 1); - int mapNum = outputLayer.getOutMapNum(); - double[] out = new double[mapNum]; - for (int m = 0; m < mapNum; m++) { - double[][] outmap = outputLayer.getMap(m); - out[m] = outmap[0][0]; - } - if (record.getLable().intValue() == Util.getMaxIndex(out)) - right++; - } - double p = 1.0 * right / trainset.size(); - Log.i("precision", p + ""); - return p; - } - - /** - * 预测结果 - * - * @param testset - * @param fileName - */ - public void predict(Dataset testset, String fileName) { - Log.i("begin predict"); - try { - int max = layers.get(layerNum - 1).getClassNum(); - PrintWriter writer = new PrintWriter(new File(fileName)); - Layer.prepareForNewBatch(); - Iterator iter = testset.iter(); - while (iter.hasNext()) { - Record record = iter.next(); - forward(record); - Layer outputLayer = layers.get(layerNum - 1); - - int mapNum = outputLayer.getOutMapNum(); - double[] out = new double[mapNum]; - for (int m = 0; m < mapNum; m++) { - double[][] outmap = outputLayer.getMap(m); - out[m] = outmap[0][0]; - } - // int lable = - // Util.binaryArray2int(out); - int lable = Util.getMaxIndex(out); - // if (lable >= max) - // lable = lable - (1 << (out.length - - // 1)); - writer.write(lable + "\n"); - } - writer.flush(); - writer.close(); - } catch (IOException e) { - throw new RuntimeException(e); - } - Log.i("end predict"); - } - - private boolean isSame(double[] output, double[] target) { - boolean r = true; - for (int i = 0; i < output.length; i++) - if (Math.abs(output[i] - target[i]) > 0.5) { - r = false; - break; - } - - return r; - } - - /** - * 训练一条记录,同时返回是否预测正确当前记录 - * - * @param record - * @return - */ - private boolean train(Record record) { - forward(record); - boolean result = backPropagation(record); - return result; - // System.exit(0); - } - - /* - * 反向传输 - */ - private boolean backPropagation(Record record) { - boolean result = setOutLayerErrors(record); - setHiddenLayerErrors(); - return result; - } - - /** - * 更新参数 - */ - private void updateParas() { - for (int l = 1; l < layerNum; l++) { - Layer layer = layers.get(l); - Layer lastLayer = layers.get(l - 1); - switch (layer.getType()) { - case conv: - case output: - updateKernels(layer, lastLayer); - updateBias(layer, lastLayer); - break; - default: - break; - } - } - } - - /** - * 更新偏置 - * - * @param layer - * @param lastLayer - */ - private void updateBias(final Layer layer, Layer lastLayer) { - final double[][][][] errors = layer.getErrors(); - int mapNum = layer.getOutMapNum(); - - new TaskManager(mapNum) { - - @Override - public void process(int start, int end) { - for (int j = start; j < end; j++) { - double[][] error = Util.sum(errors, j); - // 更新偏置 - double deltaBias = Util.sum(error) / batchSize; - double bias = layer.getBias(j) + ALPHA * deltaBias; - layer.setBias(j, bias); - } - } - }.start(); - - } - - /** - * 更新layer层的卷积核(权重)和偏置 - * - * @param layer - * 当前层 - * @param lastLayer - * 前一层 - */ - private void updateKernels(final Layer layer, final Layer lastLayer) { - int mapNum = layer.getOutMapNum(); - final int lastMapNum = lastLayer.getOutMapNum(); - new TaskManager(mapNum) { - - @Override - public void process(int start, int end) { - for (int j = start; j < end; j++) { - for (int i = 0; i < lastMapNum; i++) { - // 对batch的每个记录delta求和 - double[][] deltaKernel = null; - for (int r = 0; r < batchSize; r++) { - double[][] error = layer.getError(r, j); - if (deltaKernel == null) - deltaKernel = Util.convnValid( - lastLayer.getMap(r, i), error); - else {// 累积求和 - deltaKernel = Util.matrixOp(Util.convnValid( - lastLayer.getMap(r, i), error), - deltaKernel, null, null, Util.plus); - } - } - - // 除以batchSize - deltaKernel = Util.matrixOp(deltaKernel, - divide_batchSize); - // 更新卷积核 - double[][] kernel = layer.getKernel(i, j); - deltaKernel = Util.matrixOp(kernel, deltaKernel, - multiply_lambda, multiply_alpha, Util.plus); - layer.setKernel(i, j, deltaKernel); - } - } - - } - }.start(); - - } - - /** - * 设置中将各层的残差 - */ - private void setHiddenLayerErrors() { - for (int l = layerNum - 2; l > 0; l--) { - Layer layer = layers.get(l); - Layer nextLayer = layers.get(l + 1); - switch (layer.getType()) { - case samp: - setSampErrors(layer, nextLayer); - break; - case conv: - setConvErrors(layer, nextLayer); - break; - default:// 只有采样层和卷积层需要处理残差,输入层没有残差,输出层已经处理过 - break; - } - } - } - - /** - * 设置采样层的残差 - * - * @param layer - * @param nextLayer - */ - private void setSampErrors(final Layer layer, final Layer nextLayer) { - int mapNum = layer.getOutMapNum(); - final int nextMapNum = nextLayer.getOutMapNum(); - new TaskManager(mapNum) { - - @Override - public void process(int start, int end) { - for (int i = start; i < end; i++) { - double[][] sum = null;// 对每一个卷积进行求和 - for (int j = 0; j < nextMapNum; j++) { - double[][] nextError = nextLayer.getError(j); - double[][] kernel = nextLayer.getKernel(i, j); - // 对卷积核进行180度旋转,然后进行full模式下得卷积 - if (sum == null) - sum = Util - .convnFull(nextError, Util.rot180(kernel)); - else - sum = Util.matrixOp( - Util.convnFull(nextError, - Util.rot180(kernel)), sum, null, - null, Util.plus); - } - layer.setError(i, sum); - } - } - - }.start(); - - } - - /** - * 设置卷积层的残差 - * - * @param layer - * @param nextLayer - */ - private void setConvErrors(final Layer layer, final Layer nextLayer) { - // 卷积层的下一层为采样层,即两层的map个数相同,且一个map只与令一层的一个map连接, - // 因此只需将下一层的残差kronecker扩展再用点积即可 - int mapNum = layer.getOutMapNum(); - new TaskManager(mapNum) { - - @Override - public void process(int start, int end) { - for (int m = start; m < end; m++) { - Size scale = nextLayer.getScaleSize(); - double[][] nextError = nextLayer.getError(m); - double[][] map = layer.getMap(m); - // 矩阵相乘,但对第二个矩阵的每个元素value进行1-value操作 - double[][] outMatrix = Util.matrixOp(map, - Util.cloneMatrix(map), null, Util.one_value, - Util.multiply); - outMatrix = Util.matrixOp(outMatrix, - Util.kronecker(nextError, scale), null, null, - Util.multiply); - layer.setError(m, outMatrix); - } - - } - - }.start(); - - } - - /** - * 设置输出层的残差值,输出层的神经单元个数较少,暂不考虑多线程 - * - * @param record - * @return - */ - private boolean setOutLayerErrors(Record record) { - - Layer outputLayer = layers.get(layerNum - 1); - int mapNum = outputLayer.getOutMapNum(); - // double[] target = - // record.getDoubleEncodeTarget(mapNum); - // double[] outmaps = new double[mapNum]; - // for (int m = 0; m < mapNum; m++) { - // double[][] outmap = outputLayer.getMap(m); - // double output = outmap[0][0]; - // outmaps[m] = output; - // double errors = output * (1 - output) * - // (target[m] - output); - // outputLayer.setError(m, 0, 0, errors); - // } - // // 正确 - // if (isSame(outmaps, target)) - // return true; - // return false; - - double[] target = new double[mapNum]; - double[] outmaps = new double[mapNum]; - for (int m = 0; m < mapNum; m++) { - double[][] outmap = outputLayer.getMap(m); - outmaps[m] = outmap[0][0]; - - } - int lable = record.getLable().intValue(); - target[lable] = 1; - // Log.i(record.getLable() + "outmaps:" + - // Util.fomart(outmaps) - // + Arrays.toString(target)); - for (int m = 0; m < mapNum; m++) { - outputLayer.setError(m, 0, 0, outmaps[m] * (1 - outmaps[m]) - * (target[m] - outmaps[m])); - } - return lable == Util.getMaxIndex(outmaps); - } - - /** - * 前向计算一条记录 - * - * @param record - */ - private void forward(Record record) { - // 设置输入层的map - setInLayerOutput(record); - for (int l = 1; l < layers.size(); l++) { - Layer layer = layers.get(l); - Layer lastLayer = layers.get(l - 1); - switch (layer.getType()) { - case conv:// 计算卷积层的输出 - setConvOutput(layer, lastLayer); - break; - case samp:// 计算采样层的输出 - setSampOutput(layer, lastLayer); - break; - case output:// 计算输出层的输出,输出层是一个特殊的卷积层 - setConvOutput(layer, lastLayer); - break; - default: - break; - } - } - } - - /** - * 根据记录值,设置输入层的输出值 - * - * @param record - */ - private void setInLayerOutput(Record record) { - final Layer inputLayer = layers.get(0); - final Size mapSize = inputLayer.getMapSize(); - final double[] attr = record.getAttrs(); - if (attr.length != mapSize.x * mapSize.y) - throw new RuntimeException("数据记录的大小与定义的map大小不一致!"); - for (int i = 0; i < mapSize.x; i++) { - for (int j = 0; j < mapSize.y; j++) { - // 将记录属性的一维向量弄成二维矩阵 - inputLayer.setMapValue(0, i, j, attr[mapSize.x * i + j]); - } - } - } - - /* - * 计算卷积层输出值,每个线程负责一部分map - */ - private void setConvOutput(final Layer layer, final Layer lastLayer) { - int mapNum = layer.getOutMapNum(); - final int lastMapNum = lastLayer.getOutMapNum(); - new TaskManager(mapNum) { - - @Override - public void process(int start, int end) { - for (int j = start; j < end; j++) { - double[][] sum = null;// 对每一个输入map的卷积进行求和 - for (int i = 0; i < lastMapNum; i++) { - double[][] lastMap = lastLayer.getMap(i); - double[][] kernel = layer.getKernel(i, j); - if (sum == null) - sum = Util.convnValid(lastMap, kernel); - else - sum = Util.matrixOp( - Util.convnValid(lastMap, kernel), sum, - null, null, Util.plus); - } - final double bias = layer.getBias(j); - sum = Util.matrixOp(sum, new Operator() { - private static final long serialVersionUID = 2469461972825890810L; - - @Override - public double process(double value) { - return Util.sigmod(value + bias); - } - - }); - - layer.setMapValue(j, sum); - } - } - - }.start(); - - } - - /** - * 设置采样层的输出值,采样层是对卷积层的均值处理 - * - * @param layer - * @param lastLayer - */ - private void setSampOutput(final Layer layer, final Layer lastLayer) { - int lastMapNum = lastLayer.getOutMapNum(); - new TaskManager(lastMapNum) { - - @Override - public void process(int start, int end) { - for (int i = start; i < end; i++) { - double[][] lastMap = lastLayer.getMap(i); - Size scaleSize = layer.getScaleSize(); - // 按scaleSize区域进行均值处理 - double[][] sampMatrix = Util - .scaleMatrix(lastMap, scaleSize); - layer.setMapValue(i, sampMatrix); - } - } - - }.start(); - - } - - /** - * 设置cnn网络的每一层的参数 - * - * @param batchSize - * * @param classNum - * @param inputMapSize - */ - public void setup(int batchSize) { - Layer inputLayer = layers.get(0); - // 每一层都需要初始化输出map - inputLayer.initOutmaps(batchSize); - for (int i = 1; i < layers.size(); i++) { - Layer layer = layers.get(i); - Layer frontLayer = layers.get(i - 1); - int frontMapNum = frontLayer.getOutMapNum(); - switch (layer.getType()) { - case input: - break; - case conv: - // 设置map的大小 - layer.setMapSize(frontLayer.getMapSize().subtract( - layer.getKernelSize(), 1)); - // 初始化卷积核,共有frontMapNum*outMapNum个卷积核 - - layer.initKernel(frontMapNum); - // 初始化偏置,共有frontMapNum*outMapNum个偏置 - layer.initBias(frontMapNum); - // batch的每个记录都要保持一份残差 - layer.initErros(batchSize); - // 每一层都需要初始化输出map - layer.initOutmaps(batchSize); - break; - case samp: - // 采样层的map数量与上一层相同 - layer.setOutMapNum(frontMapNum); - // 采样层map的大小是上一层map的大小除以scale大小 - layer.setMapSize(frontLayer.getMapSize().divide( - layer.getScaleSize())); - // batch的每个记录都要保持一份残差 - layer.initErros(batchSize); - // 每一层都需要初始化输出map - layer.initOutmaps(batchSize); - break; - case output: - // 初始化权重(卷积核),输出层的卷积核大小为上一层的map大小 - layer.initOutputKerkel(frontMapNum, frontLayer.getMapSize()); - // 初始化偏置,共有frontMapNum*outMapNum个偏置 - layer.initBias(frontMapNum); - // batch的每个记录都要保持一份残差 - layer.initErros(batchSize); - // 每一层都需要初始化输出map - layer.initOutmaps(batchSize); - break; - } - } - } - - /** - * 构造者模式构造各层,要求倒数第二层必须为采样层而不能为卷积层 - * - * @author jiqunpeng - * - * 创建时间:2014-7-8 下午4:54:29 - */ - public static class LayerBuilder { - private List mLayers; - - public LayerBuilder() { - mLayers = new ArrayList(); - } - - public LayerBuilder(Layer layer) { - this(); - mLayers.add(layer); - } - - public LayerBuilder addLayer(Layer layer) { - mLayers.add(layer); - return this; - } - } - - /** - * 序列化保存模型 - * - * @param fileName - */ - public void saveModel(String fileName) { - try { - ObjectOutputStream oos = new ObjectOutputStream( - new FileOutputStream(fileName)); - oos.writeObject(this); - oos.flush(); - oos.close(); - } catch (IOException e) { - e.printStackTrace(); - } - - } - - /** - * 反序列化导入模型 - * - * @param fileName - * @return - */ - public static CNN loadModel(String fileName) { - try { - ObjectInputStream in = new ObjectInputStream(new FileInputStream( - fileName)); - CNN cnn = (CNN) in.readObject(); - in.close(); - return cnn; - } catch (IOException | ClassNotFoundException e) { - e.printStackTrace(); - } - return null; - } -} diff --git a/src/edu/hitsz/c102c/cnn/RunCNN.java b/src/edu/hitsz/c102c/cnn/RunCNN.java deleted file mode 100644 index 7f3a1c9..0000000 --- a/src/edu/hitsz/c102c/cnn/RunCNN.java +++ /dev/null @@ -1,51 +0,0 @@ -package edu.hitsz.c102c.cnn; - -import edu.hitsz.c102c.cnn.CNN.LayerBuilder; -import edu.hitsz.c102c.cnn.Layer.Size; -import edu.hitsz.c102c.dataset.Dataset; -import edu.hitsz.c102c.util.ConcurenceRunner; -import edu.hitsz.c102c.util.TimedTest; -import edu.hitsz.c102c.util.TimedTest.TestTask; - -public class RunCNN { - - public static void runCnn() { - //创建一个卷积神经网络 - LayerBuilder builder = new LayerBuilder(); - builder.addLayer(Layer.buildInputLayer(new Size(28, 28))); - builder.addLayer(Layer.buildConvLayer(6, new Size(5, 5))); - builder.addLayer(Layer.buildSampLayer(new Size(2, 2))); - builder.addLayer(Layer.buildConvLayer(12, new Size(5, 5))); - builder.addLayer(Layer.buildSampLayer(new Size(2, 2))); - builder.addLayer(Layer.buildOutputLayer(10)); - CNN cnn = new CNN(builder, 50); - - //导入数据集 - String fileName = "dataset/train.format"; - Dataset dataset = Dataset.load(fileName, ",", 784); - cnn.train(dataset, 3);// - String modelName = "model/model.cnn"; - cnn.saveModel(modelName); - dataset.clear(); - dataset = null; - - //预测 - // CNN cnn = CNN.loadModel(modelName); - Dataset testset = Dataset.load("dataset/test.format", ",", -1); - cnn.predict(testset, "dataset/test.predict"); - } - - public static void main(String[] args) { - - new TimedTest(new TestTask() { - - @Override - public void process() { - runCnn(); - } - }, 1).test(); - ConcurenceRunner.stop(); - - } - -} diff --git a/src/edu/hitsz/c102c/dataset/Dataset.java b/src/edu/hitsz/c102c/dataset/Dataset.java deleted file mode 100644 index d0291c2..0000000 --- a/src/edu/hitsz/c102c/dataset/Dataset.java +++ /dev/null @@ -1,239 +0,0 @@ -package edu.hitsz.c102c.dataset; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -public class Dataset { - // 保存数据 - private List records; - // 类别下标 - private int lableIndex; - - private double maxLable = -1; - - public Dataset(int classIndex) { - - this.lableIndex = classIndex; - records = new ArrayList(); - } - - public Dataset(List datas) { - this(); - for (double[] data : datas) { - append(new Record(data)); - } - } - - private Dataset() { - this.lableIndex = -1; - records = new ArrayList(); - } - - public int size() { - return records.size(); - } - - public int getLableIndex() { - return lableIndex; - } - - public void append(Record record) { - records.add(record); - } - - /** - * 清空数据 - */ - public void clear() { - records.clear(); - } - - /** - * 添加一个记录 - * - * @param attrs - * 记录的属性 - * @param lable - * 记录的类标 - */ - public void append(double[] attrs, Double lable) { - records.add(new Record(attrs, lable)); - } - - public Iterator iter() { - return records.iterator(); - } - - /** - * 获取第index条记录的属性 - * - * @param index - * @return - */ - public double[] getAttrs(int index) { - return records.get(index).getAttrs(); - } - - public Double getLable(int index) { - return records.get(index).getLable(); - } - - /** - * 导入数据集 - * - * @param filePath - * 文件名加路径 - * @param tag - * 字段分隔符 - * @param lableIndex - * 类标下标,从0开始 - * @return - */ - public static Dataset load(String filePath, String tag, int lableIndex) { - Dataset dataset = new Dataset(); - dataset.lableIndex = lableIndex; - File file = new File(filePath); - try { - - BufferedReader in = new BufferedReader(new FileReader(file)); - String line; - while ((line = in.readLine()) != null) { - String[] datas = line.split(tag); - if (datas.length == 0) - continue; - double[] data = new double[datas.length]; - for (int i = 0; i < datas.length; i++) - data[i] = Double.parseDouble(datas[i]); - Record record = dataset.new Record(data); - dataset.append(record); - } - in.close(); - - } catch (IOException e) { - e.printStackTrace(); - return null; - } - System.out.println("导入数据:" + dataset.size()); - return dataset; - } - - /** - * 数据记录(实例),记录由属性和类别组成,类别必须为第一列或者最后一列或者空 - * - * @author jiqunpeng - * - * 创建时间:2014-6-15 下午8:03:29 - */ - public class Record { - // 存储数据 - private double[] attrs; - private Double lable; - - private Record(double[] attrs, Double lable) { - this.attrs = attrs; - this.lable = lable; - } - - public Record(double[] data) { - if (lableIndex == -1) - attrs = data; - else { - lable = data[lableIndex]; - if (lable > maxLable) - maxLable = lable; - if (lableIndex == 0) - attrs = Arrays.copyOfRange(data, 1, data.length); - else - attrs = Arrays.copyOfRange(data, 0, data.length - 1); - } - } - - /** - * 该记录的属性 - * - * @return - */ - public double[] getAttrs() { - return attrs; - } - - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("attrs:"); - sb.append(Arrays.toString(attrs)); - sb.append("lable:"); - sb.append(lable); - return sb.toString(); - } - - /** - * 该记录的类标 - * - * @return - */ - public Double getLable() { - if (lableIndex == -1) - return null; - return lable; - } - - /** - * 对类标进行二进制编码 - * - * @param n - * @return - */ - public int[] getEncodeTarget(int n) { - String binary = Integer.toBinaryString(lable.intValue()); - byte[] bytes = binary.getBytes(); - int[] encode = new int[n]; - int j = n; - for (int i = bytes.length - 1; i >= 0; i--) - encode[--j] = bytes[i] - '0'; - - return encode; - } - - public double[] getDoubleEncodeTarget(int n) { - String binary = Integer.toBinaryString(lable.intValue()); - byte[] bytes = binary.getBytes(); - double[] encode = new double[n]; - int j = n; - for (int i = bytes.length - 1; i >= 0; i--) - encode[--j] = bytes[i] - '0'; - - return encode; - } - - } - - public static void main(String[] args) { - Dataset d = new Dataset(); - d.lableIndex = 10; - Record r = d.new Record(new double[] { 3, 2, 2, 5, 4, 5, 3, 11, 3, 12, - 1 }); - int[] encode = r.getEncodeTarget(4); - - System.out.println(r.lable); - System.out.println(Arrays.toString(encode)); - } - - /** - * 获取第index条记录 - * - * @param index - * @return - */ - public Record getRecord(int index) { - return records.get(index); - } - -} diff --git a/src/edu/hitsz/c102c/util/ConcurenceRunner.java b/src/edu/hitsz/c102c/util/ConcurenceRunner.java deleted file mode 100644 index 7a57a66..0000000 --- a/src/edu/hitsz/c102c/util/ConcurenceRunner.java +++ /dev/null @@ -1,93 +0,0 @@ -package edu.hitsz.c102c.util; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -/** - * 并发运行工具 - * - * @author jiqunpeng - * - * 创建时间:2014-6-16 下午3:33:41 - */ -public class ConcurenceRunner { - - private static final ExecutorService exec; - public static final int cpuNum; - static { - cpuNum = Runtime.getRuntime().availableProcessors(); - // cpuNum = 1; - System.out.println("cpuNum:" + cpuNum); - exec = Executors.newFixedThreadPool(cpuNum); - } - - public static void run(Runnable task) { - exec.execute(task); - } - - public static void stop() { - exec.shutdown(); - } - - // public abstract static class Task implements - // Runnable { - // int start, end; - // - // public Task(int start, int end) { - // this.start = start; - // this.end = end; - // // Log.i("new Task", - // // "start "+start+" end "+end); - // } - // - // @Override - // public void run() { - // process(start, end); - // } - // - // public abstract void process(int start, int - // end); - // - // } - - public abstract static class TaskManager { - private int workLength; - - public TaskManager(int workLength) { - this.workLength = workLength; - } - - public void start() { - int runCpu = cpuNum < workLength ? cpuNum : 1; - // 分片长度向上取整 - final CountDownLatch gate = new CountDownLatch(runCpu); - int fregLength = (workLength + runCpu - 1) / runCpu; - for (int cpu = 0; cpu < runCpu; cpu++) { - final int start = cpu * fregLength; - int tmp = (cpu + 1) * fregLength; - final int end = tmp <= workLength ? tmp : workLength; - Runnable task = new Runnable() { - - @Override - public void run() { - process(start, end); - gate.countDown(); - } - - }; - ConcurenceRunner.run(task); - } - try {// 等待所有线程跑完 - gate.await(); - } catch (InterruptedException e) { - e.printStackTrace(); - throw new RuntimeException(e); - } - } - - public abstract void process(int start, int end); - - } - -} diff --git a/src/edu/hitsz/c102c/util/Log.java b/src/edu/hitsz/c102c/util/Log.java deleted file mode 100644 index 9892816..0000000 --- a/src/edu/hitsz/c102c/util/Log.java +++ /dev/null @@ -1,16 +0,0 @@ -package edu.hitsz.c102c.util; - -import java.io.PrintStream; - -public class Log { - static PrintStream stream = System.out; - - public static void i(String tag,String msg){ - stream.println(tag+"\t"+msg); - } - - public static void i(String msg){ - stream.println(msg); - } - -} diff --git a/src/main/java/javacnn/cnn/CNN.java b/src/main/java/javacnn/cnn/CNN.java new file mode 100644 index 0000000..631362c --- /dev/null +++ b/src/main/java/javacnn/cnn/CNN.java @@ -0,0 +1,589 @@ +package javacnn.cnn; + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import javacnn.dataset.Dataset; +import javacnn.util.DotProgressIndicator; +import javacnn.util.Log; +import javacnn.util.ProgressIndicator; +import javacnn.util.Runner; +import javacnn.util.Util; + +public class CNN implements Serializable { + + private static final long serialVersionUID = 5L; + + private static final double LAMBDA = 0; + + private double ALPHA = 0.85; + + private final List layers; + private final int layerNum; + private final int batchSize; + + private final Util.Operator divide_batchSize; + private final Util.Operator multiply_alpha; + private final Util.Operator multiply_lambda; + + private transient Runner runner; + + private transient ProgressIndicator progressIndicator = new DotProgressIndicator(); + + public CNN(LayerBuilder layerBuilder, final int batchSize, final Runner runner) { + + this.layers = layerBuilder.layerList; + this.layerNum = layers.size(); + this.batchSize = batchSize; + + this.runner = runner; + + setup(batchSize); + + // --- + + final double _1_batchSize = 1. / batchSize; + + divide_batchSize = new Util.Operator() { + private static final long serialVersionUID = 7424011281732651055L; + + @Override + public double process(double value) { + return value * _1_batchSize; + } + + }; + + multiply_alpha = new Util.Operator() { + private static final long serialVersionUID = 5761368499808006552L; + + @Override + public double process(double value) { + return value * ALPHA; + } + + }; + + multiply_lambda = new Util.Operator() { + private static final long serialVersionUID = 4499087728362870577L; + + @Override + public double process(double value) { + return value * (1 - LAMBDA * ALPHA); + } + }; + } + + // === simple getters and setters === + + public void setRunner(final Runner runner) { + this.runner = runner; + } + + private Runner getRunner() { + if (runner == null) throw new NullPointerException("'runner' is null. Set runner before start training or test!"); + return runner; + } + + public ProgressIndicator getProgressIndicator() { + return progressIndicator; + } + + public void setProgressIndicator(final ProgressIndicator progressIndicator) { + this.progressIndicator = progressIndicator; + } + + // === business logic === + + public void train(final Dataset trainset, final int iterationCount) { + for (int iteration = 0; iteration < iterationCount; iteration++) { + + progressIndicator.start(); + + // separate trainset in batches of batchsize ... and round up the result + final int epochsNum = (trainset.size() + batchSize - 1) / batchSize; + + Log.info(iteration + "th iter epochsNum:" + epochsNum); + + int right = 0; + int count = 0; + + for (int epoch = 0; epoch < epochsNum; epoch++) { + + int[] randPerm = Util.randomPerm(trainset.size(), batchSize); + + Layer.prepareForNewBatch(); + + for (int index : randPerm) { + final boolean isRight = train(trainset.getRecord(index)); + if (isRight) right++; + count++; + Layer.prepareForNewRecord(); + } + + // After finishing a batch update weight + updateParas(); + + progressIndicator.progress(); + } + + progressIndicator.finished(); + + final double precision = ((double) right) / count; + + if (iteration % 10 == 1 && precision > 0.96) { + ALPHA = 0.001 + ALPHA * 0.9; // Adjust the quasi-learning rate dynamically + Log.info("Set alpha = " + ALPHA); + } + + Log.info("precision " + right + "/" + count + "=" + precision); + } + } + + public double test(final Dataset dataset) { + Layer.prepareForNewBatch(); + + final Iterator iterator = dataset.iterator(); + + int right = 0; + while (iterator.hasNext()) { + final Dataset.Record record = iterator.next(); + + final double[] out = propagate(record); + + if (record.getLabel().intValue() == Util.getMaxIndex(out)) { + right++; + } + } + + double p = 1.0 * right / dataset.size(); + + Log.info("precision", p + ""); + + return p; + } + + private double[] getOutput() { + final Layer outputLayer = layers.get(layerNum - 1); + + final int mapNum = outputLayer.getOutMapNum(); + final double[] out = new double[mapNum]; + for (int m = 0; m < mapNum; m++) { + final double[][] outmap = outputLayer.getMap(m); + out[m] = outmap[0][0]; + } + return out; + } + + // TODO: Move this method to other/new class (reduce CNN-class to the minimal CNN-logic) + public void predict(Dataset testset, String fileName) { + Log.info("begin predict"); + try { + // final int max = layers.get(layerNum - 1).getClassNum(); + final PrintWriter writer = new PrintWriter(new File(fileName)); + + Layer.prepareForNewBatch(); + + final Iterator iter = testset.iterator(); + while (iter.hasNext()) { + final Dataset.Record record = iter.next(); + final double[] out = propagate(record); + // int label = + // Util.binaryArray2int(out); + final int label = Util.getMaxIndex(out); + // if (label >= max) + // label = label - (1 << (out.length - + // 1)); + writer.write(label + "\n"); + } + writer.flush(); + writer.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + Log.info("end predict"); + } + + private boolean train(Dataset.Record record) { + forward(record); + + return backPropagation(record); + } + + private boolean backPropagation(Dataset.Record record) { + boolean result = setOutLayerErrors(record); + setHiddenLayerErrors(); + return result; + } + + private void updateParas() { + for (int l = 1; l < layerNum; l++) { + Layer layer = layers.get(l); + Layer lastLayer = layers.get(l - 1); + switch (layer.getType()) { + case conv: + case output: + updateKernels(layer, lastLayer); + updateBias(layer); + break; + default: + break; + } + } + } + + private void updateBias(final Layer layer) { + final double[][][][] errors = layer.getErrors(); + int mapNum = layer.getOutMapNum(); + + final Process processor = + new Process() { + @Override + public void process(int start, int end) { + for (int j = start; j < end; j++) { + final double[][] error = Util.sum(errors, j); + // update offset + final double deltaBias = Util.sum(error) / batchSize; + final double bias = layer.getBias(j) + ALPHA * deltaBias; + layer.setBias(j, bias); + } + } + }; + + getRunner().startProcess(mapNum, processor); + } + + private void updateKernels(final Layer layer, final Layer lastLayer) { + final int mapNum = layer.getOutMapNum(); + final int lastMapNum = lastLayer.getOutMapNum(); + + final Process process = new Process() { + @Override + public void process(int start, int end) { + for (int j = start; j < end; j++) { + for (int i = 0; i < lastMapNum; i++) { + double[][] deltaKernel = null; + for (int r = 0; r < batchSize; r++) { + final double[][] error = layer.getError(r, j); + if (deltaKernel == null) + deltaKernel = Util.convnValid(lastLayer.getMap(r, i), error); + else { + deltaKernel = Util.matrixOp(Util.convnValid(lastLayer.getMap(r, i), error), deltaKernel, null, null, Util.plus); + } + } + + deltaKernel = Util.matrixOp(deltaKernel, divide_batchSize); + final double[][] kernel = layer.getKernel(i, j); + deltaKernel = Util.matrixOp(kernel, deltaKernel, multiply_lambda, multiply_alpha, Util.plus); + layer.setKernel(i, j, deltaKernel); + } + } + + } + }; + + getRunner().startProcess(mapNum, process); + } + + private void setHiddenLayerErrors() { + for (int l = layerNum - 2; l > 0; l--) { + final Layer layer = layers.get(l); + final Layer nextLayer = layers.get(l + 1); + switch (layer.getType()) { + case samp: + setSampErrors(layer, nextLayer); + break; + case conv: + setConvErrors(layer, nextLayer); + break; + default: + break; + } + } + } + + private void setSampErrors(final Layer layer, final Layer nextLayer) { + final int mapNum = layer.getOutMapNum(); + final int nextMapNum = nextLayer.getOutMapNum(); + + final Process process = new Process() { + @Override + public void process(int start, int end) { + for (int i = start; i < end; i++) { + double[][] sum = null;// 锟斤拷每一锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷 + for (int j = 0; j < nextMapNum; j++) { + final double[][] nextError = nextLayer.getError(j); + final double[][] kernel = nextLayer.getKernel(i, j); + if (sum == null) + sum = Util.convnFull(nextError, Util.rot180(kernel)); + else + sum = Util.matrixOp(Util.convnFull(nextError, Util.rot180(kernel)), sum, null, null, Util.plus); + } + layer.setError(i, sum); + } + } + + }; + + getRunner().startProcess(mapNum, process); + } + + private void setConvErrors(final Layer layer, final Layer nextLayer) { + final int mapNum = layer.getOutMapNum(); + + final Process process = new Process() { + @Override + public void process(int start, int end) { + for (int m = start; m < end; m++) { + final Layer.Size scale = nextLayer.getScaleSize(); + final double[][] nextError = nextLayer.getError(m); + final double[][] map = layer.getMap(m); + double[][] outMatrix = Util.matrixOp(map, Util.cloneMatrix(map), null, Util.one_value, Util.multiply); + outMatrix = Util.matrixOp(outMatrix, Util.kronecker(nextError, scale), null, null, Util.multiply); + layer.setError(m, outMatrix); + } + } + }; + + getRunner().startProcess(mapNum, process); + } + + private boolean setOutLayerErrors(final Dataset.Record record) { + + final Layer outputLayer = layers.get(layerNum - 1); + final int mapNum = outputLayer.getOutMapNum(); + final double[] target = new double[mapNum]; + final double[] outmaps = new double[mapNum]; + + for (int m = 0; m < mapNum; m++) { + final double[][] outmap = outputLayer.getMap(m); + outmaps[m] = outmap[0][0]; + } + + final int label = record.getLabel().intValue(); + + target[label] = 1; + + for (int m = 0; m < mapNum; m++) { + outputLayer.setError(m, 0, 0, outmaps[m] * (1 - outmaps[m]) * (target[m] - outmaps[m])); + } + + return label == Util.getMaxIndex(outmaps); + } + + /** + * Propagate given values through the network. + * Returns the results. + * For each input it returns the set of output values. + * + * @param inputs A list of vectors of input values + * @return A list of results of the network corresponding to each input vector + */ + public double[][] propagate(final double[][] inputs) { + final double[][] results = new double[inputs.length][]; + + int index = 0; + for (final double[] input : inputs) { + final Dataset.Record record = new Dataset.Record(input, -1.); + results[index] = propagate(record); + index++; + } + + return results; + } + + /** + * Propagate given values through the network. + * Returns the result. + * + * @param inputs A vector of input values + * @return The result of the network + */ + public double[] propagate(final double[] inputs) { + final Dataset.Record record = new Dataset.Record(inputs, -1.); + + return propagate(record); + } + + /** + * Propagate given Record through the network. + * Returns the result. + * + * @param record A Record + * @return The result of the network + */ + public double[] propagate(final Dataset.Record record) { + forward(record); + + return getOutput(); + } + + private void forward(final Dataset.Record record) { + setInLayerOutput(record); + + for (int l = 1; l < layers.size(); l++) { + final Layer layer = layers.get(l); + final Layer lastLayer = layers.get(l - 1); + + switch (layer.getType()) { + case conv: + setConvOutput(layer, lastLayer); + break; + + case samp: + setSampOutput(layer, lastLayer); + break; + + case output: + setConvOutput(layer, lastLayer); + break; + + default: + break; + } + } + } + + private void setInLayerOutput(final Dataset.Record record) { + final Layer inputLayer = layers.get(0); + final Layer.Size mapSize = inputLayer.getMapSize(); + + final double[] attr = record.getAttrs(); + + if (attr.length != mapSize.x * mapSize.y) { + throw new RuntimeException("The size of the data record does not match the size of the map defined!"); + } + + for (int i = 0; i < mapSize.x; i++) { + for (int j = 0; j < mapSize.y; j++) { + inputLayer.setMapValue(0, i, j, attr[mapSize.x * i + j]); + } + } + } + + /** + * Compute the output of the convolutional layer, each thread is responsible for part of the map + */ + private void setConvOutput(final Layer layer, final Layer lastLayer) { + final int mapNum = layer.getOutMapNum(); + final int lastMapNum = lastLayer.getOutMapNum(); + + final Process process = new Process() { + @Override + public void process(int start, int end) { + for (int j = start; j < end; j++) { + double[][] sum = null; + for (int i = 0; i < lastMapNum; i++) { + final double[][] lastMap = lastLayer.getMap(i); + final double[][] kernel = layer.getKernel(i, j); + if (sum == null) { + sum = Util.convnValid(lastMap, kernel); + } else { + sum = Util.matrixOp(Util.convnValid(lastMap, kernel), sum, null, null, Util.plus); + } + } + final double bias = layer.getBias(j); + sum = Util + .matrixOp( + sum, + new Util.Operator() { + private static final long serialVersionUID = 2469461972825890810L; + + @Override + public double process(double value) { + return Util.sigmod(value + bias); + } + } + ); + + layer.setMapValue(j, sum); + } + } + }; + + getRunner().startProcess(mapNum, process); + } + + private void setSampOutput(final Layer layer, final Layer lastLayer) { + final int lastMapNum = lastLayer.getOutMapNum(); + + final Process process = new Process() { + @Override + public void process(int start, int end) { + for (int i = start; i < end; i++) { + final double[][] lastMap = lastLayer.getMap(i); + final Layer.Size scaleSize = layer.getScaleSize(); + final double[][] sampMatrix = Util.scaleMatrix(lastMap, scaleSize); + layer.setMapValue(i, sampMatrix); + } + } + }; + + getRunner().startProcess(lastMapNum, process); + } + + private void setup(final int batchSize) { + final Layer inputLayer = layers.get(0); + + inputLayer.initOutmaps(batchSize); + + for (int i = 1; i < layers.size(); i++) { + + final Layer layer = layers.get(i); + final Layer frontLayer = layers.get(i - 1); + + final int frontMapNum = frontLayer.getOutMapNum(); + switch (layer.getType()) { + case input: + break; + case conv: + layer.setMapSize(frontLayer.getMapSize().subtract(layer.getKernelSize(), 1)); + layer.initKernel(frontMapNum); + layer.initBias(frontMapNum); + layer.initErros(batchSize); + layer.initOutmaps(batchSize); + break; + + case samp: + layer.setOutMapNum(frontMapNum); + layer.setMapSize(frontLayer.getMapSize().divide(layer.getScaleSize())); + layer.initErros(batchSize); + layer.initOutmaps(batchSize); + break; + + case output: + layer.initOutputKerkel(frontMapNum, frontLayer.getMapSize()); + layer.initBias(frontMapNum); + layer.initErros(batchSize); + layer.initOutmaps(batchSize); + break; + } + } + } + + // === inner classes === + + public static class LayerBuilder { + private List layerList; + + public LayerBuilder() { + layerList = new ArrayList<>(); + } + + public LayerBuilder(Layer layer) { + this(); + layerList.add(layer); + } + + public LayerBuilder addLayer(Layer layer) { + layerList.add(layer); + return this; + } + } + +} diff --git a/src/main/java/javacnn/cnn/CNNLoader.java b/src/main/java/javacnn/cnn/CNNLoader.java new file mode 100644 index 0000000..b084bba --- /dev/null +++ b/src/main/java/javacnn/cnn/CNNLoader.java @@ -0,0 +1,36 @@ +package javacnn.cnn; + +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.OutputStream; + +public class CNNLoader { + + public static void saveModel(final String fileName, final CNN cnn) throws IOException { + saveModel(cnn, new FileOutputStream(fileName)); + } + + public static void saveModel(final CNN cnn, final OutputStream outputStream) throws IOException { + ObjectOutputStream oos = new ObjectOutputStream(outputStream); + oos.writeObject(cnn); + oos.flush(); + oos.close(); + } + + public static CNN loadModel(final String fileName) throws IOException, ClassNotFoundException { + return loadModel(new FileInputStream(fileName)); + } + + public static CNN loadModel(final InputStream inputStream) throws IOException, ClassNotFoundException { + final ObjectInputStream in = new ObjectInputStream(inputStream); + final CNN cnn = (CNN) in.readObject(); + in.close(); + + return cnn; + } + +} diff --git a/src/edu/hitsz/c102c/cnn/Layer.java b/src/main/java/javacnn/cnn/Layer.java similarity index 64% rename from src/edu/hitsz/c102c/cnn/Layer.java rename to src/main/java/javacnn/cnn/Layer.java index adf78e4..5d9599f 100644 --- a/src/edu/hitsz/c102c/cnn/Layer.java +++ b/src/main/java/javacnn/cnn/Layer.java @@ -1,75 +1,56 @@ -package edu.hitsz.c102c.cnn; +package javacnn.cnn; import java.io.Serializable; -import edu.hitsz.c102c.util.Log; -import edu.hitsz.c102c.util.Util; +import javacnn.util.Log; +import javacnn.util.Util; /** - * cnn网络的层 - * + * cnn锟斤拷锟斤拷牟锟 + * * @author jiqunpeng - * - * 创建时间:2014-7-8 下午3:58:46 + *

+ * 锟斤拷锟斤拷时锟戒:2014-7-8 锟斤拷锟斤拷3:58:46 */ public class Layer implements Serializable { /** - * + * */ private static final long serialVersionUID = -5747622503947497069L; - private LayerType type;// 层的类型 - private int outMapNum;// 输出map的个数 - private Size mapSize;// map的大小 - private Size kernelSize;// 卷积核大小,只有卷积层有 - private Size scaleSize;// 采样大小,只有采样层有 - private double[][][][] kernel;// 卷积核,只有卷积层和输出层有 - private double[] bias;// 每个map对应一个偏置,只有卷积层和输出层有 - // 保存各个batch的输出map,outmaps[0][0]表示第一条记录训练下第0个输出map + private LayerType type; + private int outMapNum; + private Size mapSize; + private Size kernelSize; + private Size scaleSize; + private double[][][][] kernel; + private double[] bias; private double[][][][] outmaps; - // 残差,与matlab toolbox的d对应 private double[][][][] errors; - private static int recordInBatch = 0;// 记录当前训练的是batch的第几条记录 + private static int recordInBatch = 0; - private int classNum = -1;// 类别个数 + private int classNum = -1; private Layer() { } - /** - * 准备下一个batch的训练 - */ public static void prepareForNewBatch() { recordInBatch = 0; } - /** - * 准备下一条记录的训练 - */ public static void prepareForNewRecord() { recordInBatch++; } - /** - * 初始化输入层 - * - * @param mapSize - * @return - */ public static Layer buildInputLayer(Size mapSize) { Layer layer = new Layer(); layer.type = LayerType.input; - layer.outMapNum = 1;// 输入层的map个数为1,即一张图 + layer.outMapNum = 1;// 锟斤拷锟斤拷锟斤拷map锟斤拷锟斤拷为1锟斤拷锟斤拷一锟斤拷图 layer.setMapSize(mapSize);// return layer; } - /** - * 构造卷积层 - * - * @return - */ public static Layer buildConvLayer(int outMapNum, Size kernelSize) { Layer layer = new Layer(); layer.type = LayerType.conv; @@ -78,12 +59,6 @@ public static Layer buildConvLayer(int outMapNum, Size kernelSize) { return layer; } - /** - * 构造采样层 - * - * @param scaleSize - * @return - */ public static Layer buildSampLayer(Size scaleSize) { Layer layer = new Layer(); layer.type = LayerType.samp; @@ -91,11 +66,6 @@ public static Layer buildSampLayer(Size scaleSize) { return layer; } - /** - * 构造输出层,类别个数,根据类别的个数来决定输出单元的个数 - * - * @return - */ public static Layer buildOutputLayer(int classNum) { Layer layer = new Layer(); layer.classNum = classNum; @@ -106,86 +76,44 @@ public static Layer buildOutputLayer(int classNum) { // while ((1 << outMapNum) < classNum) // outMapNum += 1; // layer.outMapNum = outMapNum; - Log.i("outMapNum:" + layer.outMapNum); + Log.info("outMapNum:" + layer.outMapNum); return layer; } - /** - * 获取map的大小 - * - * @return - */ public Size getMapSize() { return mapSize; } - /** - * 设置map的大小 - * - * @param mapSize - */ public void setMapSize(Size mapSize) { this.mapSize = mapSize; } - /** - * 获取层的类型 - * - * @return - */ public LayerType getType() { return type; } - /** - * 获取输出向量个数 - * - * @return - */ - public int getOutMapNum() { return outMapNum; } - /** - * 设置输出map的个数 - * - * @param outMapNum - */ public void setOutMapNum(int outMapNum) { this.outMapNum = outMapNum; } - /** - * 获取卷积核的大小,只有卷积层有kernelSize,其他层均未null - * - * @return - */ public Size getKernelSize() { return kernelSize; } - /** - * 获取采样大小,只有采样层有scaleSize,其他层均未null - * - * @return - */ public Size getScaleSize() { return scaleSize; } enum LayerType { - // 网络层的类型:输入层、输出层、卷积层、采样层 input, output, conv, samp } - /** - * 卷积核或者采样层scale的大小,长与宽可以不等.类型安全,定以后不可修改 - * - * @author jiqunpeng - * - * 创建时间:2014-7-8 下午4:11:00 - */ + // --- + public static class Size implements Serializable { private static final long serialVersionUID = -209157832162004118L; @@ -197,30 +125,34 @@ public Size(int x, int y) { this.y = y; } + @Override public String toString() { - StringBuilder s = new StringBuilder("Size(").append(" x = ") - .append(x).append(" y= ").append(y).append(")"); - return s.toString(); + return "Size{" + + "x=" + x + + ", y=" + y + + '}'; } /** - * 整除scaleSize得到一个新的Size,要求this.x、this. - * y能分别被scaleSize.x、scaleSize.y整除 - * + * 锟斤拷锟斤拷scaleSize锟矫碉拷一锟斤拷锟铰碉拷Size锟斤拷要锟斤拷this.x锟斤拷this. + * y锟杰分憋拷scaleSize.x锟斤拷scaleSize.y锟斤拷锟斤拷 + * * @param scaleSize * @return */ public Size divide(Size scaleSize) { int x = this.x / scaleSize.x; int y = this.y / scaleSize.y; - if (x * scaleSize.x != this.x || y * scaleSize.y != this.y) - throw new RuntimeException(this + "不能整除" + scaleSize); + if (x * scaleSize.x != this.x || y * scaleSize.y != this.y) { + throw new RuntimeException(this + " can not be divisible " + scaleSize); + } + return new Size(x, y); } /** - * 减去size大小,并x和y分别附加一个值append - * + * 锟斤拷去size锟斤拷小锟斤拷锟斤拷x锟斤拷y锟街别附硷拷一锟斤拷值append + * * @param size * @param append * @return @@ -233,8 +165,8 @@ public Size subtract(Size size, int append) { } /** - * 随机初始化卷积核 - * + * 锟斤拷锟斤拷锟绞硷拷锟斤拷锟斤拷锟斤拷 + * * @param frontMapNum */ public void initKernel(int frontMapNum) { @@ -244,12 +176,12 @@ public void initKernel(int frontMapNum) { this.kernel = new double[frontMapNum][outMapNum][kernelSize.x][kernelSize.y]; for (int i = 0; i < frontMapNum; i++) for (int j = 0; j < outMapNum; j++) - kernel[i][j] = Util.randomMatrix(kernelSize.x, kernelSize.y,true); + kernel[i][j] = Util.randomMatrix(kernelSize.x, kernelSize.y, true); } /** - * 输出层的卷积核的大小是上一层的map大小 - * + * 锟斤拷锟斤拷锟侥撅拷锟斤拷说拇锟叫★拷锟斤拷锟揭伙拷锟斤拷map锟斤拷小 + * * @param frontMapNum * @param size */ @@ -261,12 +193,12 @@ public void initOutputKerkel(int frontMapNum, Size size) { this.kernel = new double[frontMapNum][outMapNum][kernelSize.x][kernelSize.y]; for (int i = 0; i < frontMapNum; i++) for (int j = 0; j < outMapNum; j++) - kernel[i][j] = Util.randomMatrix(kernelSize.x, kernelSize.y,false); + kernel[i][j] = Util.randomMatrix(kernelSize.x, kernelSize.y, false); } /** - * 初始化偏置 - * + * 锟斤拷始锟斤拷偏锟斤拷 + * * @param frontMapNum */ public void initBias(int frontMapNum) { @@ -274,8 +206,8 @@ public void initBias(int frontMapNum) { } /** - * 初始化输出map - * + * 锟斤拷始锟斤拷锟斤拷锟絤ap + * * @param batchSize */ public void initOutmaps(int batchSize) { @@ -283,14 +215,11 @@ public void initOutmaps(int batchSize) { } /** - * 设置map值 - * - * @param mapNo - * 第几个map - * @param mapX - * map的高 - * @param mapY - * map的宽 + * 锟斤拷锟斤拷map值 + * + * @param mapNo 锟节硷拷锟斤拷map + * @param mapX map锟侥革拷 + * @param mapY map锟侥匡拷 * @param value */ public void setMapValue(int mapNo, int mapX, int mapY, double value) { @@ -300,8 +229,8 @@ public void setMapValue(int mapNo, int mapX, int mapY, double value) { static int count = 0; /** - * 以矩阵形式设置第mapNo个map的值 - * + * 锟皆撅拷锟斤拷锟斤拷式锟斤拷锟矫碉拷mapNo锟斤拷map锟斤拷值 + * * @param mapNo * @param outMatrix */ @@ -312,9 +241,9 @@ public void setMapValue(int mapNo, double[][] outMatrix) { } /** - * 获取第index个map矩阵。处于性能考虑,没有返回复制对象,而是直接返回引用,调用端请谨慎, - * 避免修改outmaps,如需修改请调用setMapValue(...) - * + * 锟斤拷取锟斤拷index锟斤拷map锟斤拷锟襟。达拷锟斤拷锟斤拷锟杰匡拷锟角o拷没锟叫凤拷锟截革拷锟狡讹拷锟襟,讹拷锟斤拷直锟接凤拷锟斤拷锟斤拷锟矫o拷锟斤拷锟矫讹拷锟斤拷锟斤拷锟斤拷锟 + * 锟斤拷锟斤拷锟睫革拷outmaps锟斤拷锟斤拷锟斤拷锟睫革拷锟斤拷锟斤拷锟絪etMapValue(...) + * * @param index * @return */ @@ -323,12 +252,10 @@ public double[][] getMap(int index) { } /** - * 获取前一层第i个map到当前层第j个map的卷积核 - * - * @param i - * 上一层的map下标 - * @param j - * 当前层的map下标 + * 锟斤拷取前一锟斤拷锟絠锟斤拷map锟斤拷锟斤拷前锟斤拷锟絡锟斤拷map锟侥撅拷锟斤拷锟 + * + * @param i 锟斤拷一锟斤拷锟絤ap锟铰憋拷 + * @param j 锟斤拷前锟斤拷锟絤ap锟铰憋拷 * @return */ public double[][] getKernel(int i, int j) { @@ -336,8 +263,8 @@ public double[][] getKernel(int i, int j) { } /** - * 设置残差值 - * + * 锟斤拷锟矫残诧拷值 + * * @param mapNo * @param mapX * @param mapY @@ -348,8 +275,8 @@ public void setError(int mapNo, int mapX, int mapY, double value) { } /** - * 以map矩阵块形式设置残差值 - * + * 锟斤拷map锟斤拷锟斤拷锟斤拷锟绞斤拷锟斤拷貌胁锟街 + * * @param mapNo * @param matrix */ @@ -360,9 +287,9 @@ public void setError(int mapNo, double[][] matrix) { } /** - * 获取第mapNo个map的残差.没有返回复制对象,而是直接返回引用,调用端请谨慎, - * 避免修改errors,如需修改请调用setError(...) - * + * 锟斤拷取锟斤拷mapNo锟斤拷map锟侥残诧拷.没锟叫凤拷锟截革拷锟狡讹拷锟襟,讹拷锟斤拷直锟接凤拷锟斤拷锟斤拷锟矫o拷锟斤拷锟矫讹拷锟斤拷锟斤拷锟斤拷锟 + * 锟斤拷锟斤拷锟睫革拷errors锟斤拷锟斤拷锟斤拷锟睫革拷锟斤拷锟斤拷锟絪etError(...) + * * @param mapNo * @return */ @@ -371,8 +298,8 @@ public double[][] getError(int mapNo) { } /** - * 获取所有(每个记录和每个map)的残差 - * + * 锟斤拷取锟斤拷锟斤拷(每锟斤拷锟斤拷录锟斤拷每锟斤拷map)锟侥残诧拷 + * * @return */ public double[][][][] getErrors() { @@ -380,8 +307,8 @@ public double[][][][] getErrors() { } /** - * 初始化残差数组 - * + * 锟斤拷始锟斤拷锟叫诧拷锟斤拷锟斤拷 + * * @param batchSize */ public void initErros(int batchSize) { @@ -389,7 +316,6 @@ public void initErros(int batchSize) { } /** - * * @param lastMapNo * @param mapNo * @param kernel @@ -399,8 +325,8 @@ public void setKernel(int lastMapNo, int mapNo, double[][] kernel) { } /** - * 获取第mapNo个 - * + * 锟斤拷取锟斤拷mapNo锟斤拷 + * * @param mapNo * @return */ @@ -409,8 +335,8 @@ public double getBias(int mapNo) { } /** - * 设置第mapNo个map的偏置值 - * + * 锟斤拷锟矫碉拷mapNo锟斤拷map锟斤拷偏锟斤拷值 + * * @param mapNo * @param value */ @@ -419,8 +345,8 @@ public void setBias(int mapNo, double value) { } /** - * 获取batch各个map矩阵 - * + * 锟斤拷取batch锟斤拷锟斤拷map锟斤拷锟斤拷 + * * @return */ @@ -429,8 +355,8 @@ public double[][][][] getMaps() { } /** - * 获取第recordId记录下第mapNo的残差 - * + * 锟斤拷取锟斤拷recordId锟斤拷录锟铰碉拷mapNo锟侥残诧拷 + * * @param recordId * @param mapNo * @return @@ -440,8 +366,8 @@ public double[][] getError(int recordId, int mapNo) { } /** - * 获取第recordId记录下第mapNo的输出map - * + * 锟斤拷取锟斤拷recordId锟斤拷录锟铰碉拷mapNo锟斤拷锟斤拷锟絤ap + * * @param recordId * @param mapNo * @return @@ -451,8 +377,8 @@ public double[][] getMap(int recordId, int mapNo) { } /** - * 获取类别个数 - * + * 锟斤拷取锟斤拷锟斤拷锟斤拷 + * * @return */ public int getClassNum() { @@ -460,8 +386,8 @@ public int getClassNum() { } /** - * 获取所有的卷积核 - * + * 锟斤拷取锟斤拷锟叫的撅拷锟斤拷锟 + * * @return */ public double[][][][] getKernel() { diff --git a/src/main/java/javacnn/cnn/Process.java b/src/main/java/javacnn/cnn/Process.java new file mode 100644 index 0000000..0ba7194 --- /dev/null +++ b/src/main/java/javacnn/cnn/Process.java @@ -0,0 +1,11 @@ +package javacnn.cnn; + +/** + *

+ * Created: 2018-02-19 08:29 + * + * @author Ralf Th. Pietsch <ratopi@abwesend.de> + */ +public interface Process { + void process(int start, int end); +} diff --git a/src/main/java/javacnn/dataset/Dataset.java b/src/main/java/javacnn/dataset/Dataset.java new file mode 100644 index 0000000..877d47b --- /dev/null +++ b/src/main/java/javacnn/dataset/Dataset.java @@ -0,0 +1,89 @@ +package javacnn.dataset; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +public class Dataset { + private List records; + + public Dataset() { + records = new ArrayList<>(); + } + + public Dataset(final List datas, final List labels) { + this(); + + if (datas.size() != labels.size()) { + throw new IllegalArgumentException("Lengths differs: " + datas.size() + " datas and " + labels.size() + " labels"); + } + + for (int i = 0; i < datas.size(); i++) { + final double[] data = datas.get(i); + final Double label = labels.get(i); + append(new Record(data, label)); + } + } + + public int size() { + return records.size(); + } + + public void append(Record record) { + records.add(record); + } + + public void clear() { + records.clear(); + } + + public void append(double[] attrs, Double label) { + records.add(new Record(attrs, label)); + } + + public Iterator iterator() { + return records.iterator(); + } + + public double[] getAttrs(int index) { + return records.get(index).getAttrs(); + } + + public Double getLabel(int index) { + return records.get(index).getLabel(); + } + + public Record getRecord(int index) { + return records.get(index); + } + + // --- + + public static class Record { + private double[] attrs; + private Double label; + + public Record(double[] attrs, Double label) { + this.attrs = attrs; + this.label = label; + } + + public double[] getAttrs() { + return attrs; + } + + public Double getLabel() { + return label; + } + + @Override + public String toString() { + return "Record{" + + "attrs=" + Arrays.toString(attrs) + + ", label=" + label + + '}'; + } + } + +} diff --git a/src/main/java/javacnn/dataset/DatasetLoader.java b/src/main/java/javacnn/dataset/DatasetLoader.java new file mode 100644 index 0000000..f5a663d --- /dev/null +++ b/src/main/java/javacnn/dataset/DatasetLoader.java @@ -0,0 +1,41 @@ +package javacnn.dataset; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; + +public class DatasetLoader { + public static Dataset load(final String filePath, final String tag, final int labelIndex) throws IOException { + final Dataset dataset = new Dataset(); + + final BufferedReader in = new BufferedReader(new FileReader(filePath)); + + String line; + while ((line = in.readLine()) != null) { + + final String[] datas = line.split(tag); + + if (datas.length == 0) { + continue; + } + + final int vectorLength = labelIndex < 0 ? datas.length : datas.length - 1; + + final double[] data = new double[vectorLength]; + + for (int i = 0; i < vectorLength; i++) { + data[i] = Double.parseDouble(datas[i]); + } + + final Double label = labelIndex < 0 ? null : Double.parseDouble(datas[labelIndex]); + + dataset.append(data, label); + } + in.close(); + + System.out.println("Read " + dataset.size() + " records"); + + return dataset; + } + +} diff --git a/src/main/java/javacnn/util/ConcurenceRunner.java b/src/main/java/javacnn/util/ConcurenceRunner.java new file mode 100644 index 0000000..e364195 --- /dev/null +++ b/src/main/java/javacnn/util/ConcurenceRunner.java @@ -0,0 +1,75 @@ +package javacnn.util; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import javacnn.cnn.Process; + +/** + * Concurrent running tools + *

+ * Created: 2014-6-16 at 3:33:41 PM + * + * @author jiqunpeng + */ +public class ConcurenceRunner implements Runner { + + private final ExecutorService exec; + private final int threadCount; + + /** + * Starting ConcurrenceRunner with one thread for each CPU. + */ + public ConcurenceRunner() { + this(Runtime.getRuntime().availableProcessors()); + } + + /** + * Starting ConcurenceRunner with the given count of threads. + * + * @param threadCount Threads to start (must be > 0). + */ + public ConcurenceRunner(final int threadCount) { + this.threadCount = threadCount; + exec = Executors.newFixedThreadPool(this.threadCount); + } + + public void shutdown() { + exec.shutdown(); + } + + @Override + public void startProcess(final int mapNum, final Process process) { + final int runCpu = threadCount < mapNum ? threadCount : 1; + + // Fragment length rounded up + final CountDownLatch gate = new CountDownLatch(runCpu); + + final int fregLength = (mapNum + runCpu - 1) / runCpu; + + for (int cpu = 0; cpu < runCpu; cpu++) { + final int start = cpu * fregLength; + + final int tmp = (cpu + 1) * fregLength; + final int end = tmp <= mapNum ? tmp : mapNum; + + final Runnable task = new Runnable() { + @Override + public void run() { + process.process(start, end); + gate.countDown(); + } + }; + + exec.execute(task); + } + try {// Wait for all threads to finish running + gate.await(); + } catch (InterruptedException e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + } + +} diff --git a/src/main/java/javacnn/util/DirectRunner.java b/src/main/java/javacnn/util/DirectRunner.java new file mode 100644 index 0000000..ad8bd4c --- /dev/null +++ b/src/main/java/javacnn/util/DirectRunner.java @@ -0,0 +1,29 @@ +package javacnn.util; + +import javacnn.cnn.Process; + +/** + *

+ * Created: 20.02.2018 11:03 + * + * @author Ralf Th. Pietsch <ratopi@abwesend.de> + */ +public class DirectRunner implements Runner { + + @Override + public void startProcess(final int mapNum, final Process process) { + final int runCpu = 1; + + // Fragment length rounded up + final int fregLength = (mapNum + runCpu - 1) / runCpu; + + for (int cpu = 0; cpu < runCpu; cpu++) { + final int start = cpu * fregLength; + + final int tmp = (cpu + 1) * fregLength; + final int end = tmp <= mapNum ? tmp : mapNum; + + process.process(start, end); + } + } +} diff --git a/src/main/java/javacnn/util/DotProgressIndicator.java b/src/main/java/javacnn/util/DotProgressIndicator.java new file mode 100644 index 0000000..5996de8 --- /dev/null +++ b/src/main/java/javacnn/util/DotProgressIndicator.java @@ -0,0 +1,47 @@ +package javacnn.util; + +import java.io.Serializable; + +/** + *

+ * Created: 19.02.2018 10:53 + * + * @author Ralf Th. Pietsch <ratopi@abwesend.de> + */ +public class DotProgressIndicator implements ProgressIndicator, Serializable { + + private static final long serialVersionUID = 1L; + + private int cycle; + + private int count = 0; + + + public DotProgressIndicator() { + this(50); + } + + public DotProgressIndicator(final int cycle) { + this.cycle = cycle; + } + + + @Override + public void start() { + count = 0; + } + + @Override + public void progress() { + count++; + if (count > cycle) { + System.out.print("."); + count = 0; + } + } + + @Override + public void finished() { + System.out.println(); + } +} diff --git a/src/main/java/javacnn/util/Log.java b/src/main/java/javacnn/util/Log.java new file mode 100644 index 0000000..683cc86 --- /dev/null +++ b/src/main/java/javacnn/util/Log.java @@ -0,0 +1,22 @@ +package javacnn.util; + +import java.io.PrintStream; + +public class Log { + private static final PrintStream stream = System.out; + + private static boolean on = false; + + public static void switchOn() { + on = true; + } + + public static void info(String tag, String msg) { + if (on) stream.println(tag + "\t" + msg); + } + + public static void info(String msg) { + if (on) stream.println(msg); + } + +} diff --git a/src/main/java/javacnn/util/ProgressIndicator.java b/src/main/java/javacnn/util/ProgressIndicator.java new file mode 100644 index 0000000..1bb4af4 --- /dev/null +++ b/src/main/java/javacnn/util/ProgressIndicator.java @@ -0,0 +1,14 @@ +package javacnn.util; + +/** + * Interface for feedback progress of any kind + *

+ * Created: 19.02.2018 10:52 + * + * @author Ralf Th. Pietsch <ratopi@abwesend.de> + */ +public interface ProgressIndicator { + void start(); + void progress(); + void finished(); +} diff --git a/src/main/java/javacnn/util/Runner.java b/src/main/java/javacnn/util/Runner.java new file mode 100644 index 0000000..b404a49 --- /dev/null +++ b/src/main/java/javacnn/util/Runner.java @@ -0,0 +1,13 @@ +package javacnn.util; + +import javacnn.cnn.Process; + +/** + *

+ * Created: 2018-02-19 08:57 + * + * @author Ralf Th. Pietsch <ratopi@abwesend.de> + */ +public interface Runner { + void startProcess(int mapNum, Process process); +} diff --git a/src/edu/hitsz/c102c/util/TestArray.java b/src/main/java/javacnn/util/TestArray.java similarity index 73% rename from src/edu/hitsz/c102c/util/TestArray.java rename to src/main/java/javacnn/util/TestArray.java index b946432..4ccf55f 100644 --- a/src/edu/hitsz/c102c/util/TestArray.java +++ b/src/main/java/javacnn/util/TestArray.java @@ -1,15 +1,15 @@ -package edu.hitsz.c102c.util; +package javacnn.util; import java.util.Locale; -import edu.hitsz.c102c.util.TimedTest.TestTask; +import javacnn.util.TimedTest.TestTask; /** - * 测试元素直接访问数组与通过函数访问数组的效率, 结论:函数形式访问并没有降低速度 + * 锟斤拷锟斤拷元锟斤拷直锟接凤拷锟斤拷锟斤拷锟斤拷锟斤拷通锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟叫э拷剩锟 锟斤拷锟桔o拷锟斤拷锟斤拷锟斤拷式锟斤拷锟绞诧拷没锟叫斤拷锟斤拷锟劫讹拷 * * @author jiqunpeng * - * 创建时间:2014-7-9 下午3:18:30 + * 锟斤拷锟斤拷时锟戒:2014-7-9 锟斤拷锟斤拷3:18:30 */ public class TestArray { double[][] data; @@ -35,7 +35,7 @@ private void useFunc() { } public static void main(String[] args) { - String a = "aAdfa彭_"; + String a = "aAdfa锟斤拷_"; System.out.println(a.toUpperCase(Locale.CHINA)); double[][] d = new double[3][]; // d[0] = new double[] { 1,2,3 }; diff --git a/src/edu/hitsz/c102c/util/TimedTest.java b/src/main/java/javacnn/util/TimedTest.java similarity index 74% rename from src/edu/hitsz/c102c/util/TimedTest.java rename to src/main/java/javacnn/util/TimedTest.java index 71125aa..ea5959c 100644 --- a/src/edu/hitsz/c102c/util/TimedTest.java +++ b/src/main/java/javacnn/util/TimedTest.java @@ -1,11 +1,11 @@ -package edu.hitsz.c102c.util; +package javacnn.util; /** - * 计时的测试工具 + * 锟斤拷时锟侥诧拷锟皆癸拷锟斤拷 * * @author jiqunpeng * - * 创建时间:2014-7-8 下午8:21:56 + * 锟斤拷锟斤拷时锟戒:2014-7-8 锟斤拷锟斤拷8:21:56 */ public class TimedTest { private int repeat; @@ -26,6 +26,6 @@ public void test() { task.process(); } double cost = (System.currentTimeMillis() - t) / 1000.0; - Log.i("cost ", cost + "s"); + Log.info("cost ", cost + "s"); } } diff --git a/src/edu/hitsz/c102c/util/Util.java b/src/main/java/javacnn/util/Util.java similarity index 84% rename from src/edu/hitsz/c102c/util/Util.java rename to src/main/java/javacnn/util/Util.java index e0d0077..62b3020 100644 --- a/src/edu/hitsz/c102c/util/Util.java +++ b/src/main/java/javacnn/util/Util.java @@ -1,27 +1,26 @@ -package edu.hitsz.c102c.util; +package javacnn.util; import java.io.Serializable; import java.util.Arrays; import java.util.HashSet; import java.util.Random; import java.util.Set; -import edu.hitsz.c102c.cnn.Layer.Size; -import edu.hitsz.c102c.util.TimedTest.TestTask; +import javacnn.cnn.Layer.Size; public class Util { /** - * 矩阵对应元素相乘时在每个元素上的操作 + * 锟斤拷锟斤拷锟接υ拷锟斤拷锟斤拷时锟斤拷每锟斤拷元锟斤拷锟较的诧拷锟斤拷 * * @author jiqunpeng * - * 创建时间:2014-7-9 下午9:28:35 + * 锟斤拷锟斤拷时锟戒:2014-7-9 锟斤拷锟斤拷9:28:35 */ public interface Operator extends Serializable { public double process(double value); } - // 定义每个元素value都进行1-value的操作 + // 锟斤拷锟斤拷每锟斤拷元锟斤拷value锟斤拷锟斤拷锟斤拷1-value锟侥诧拷锟斤拷 public static final Operator one_value = new Operator() { /** * @@ -34,7 +33,7 @@ public double process(double value) { } }; - // digmod函数 + // digmod锟斤拷锟斤拷 public static final Operator digmod = new Operator() { /** * @@ -52,7 +51,7 @@ interface OperatorOnTwo extends Serializable { } /** - * 定义矩阵对应元素的加法操作 + * 锟斤拷锟斤拷锟斤拷锟斤拷应元锟截的加凤拷锟斤拷锟斤拷 */ public static final OperatorOnTwo plus = new OperatorOnTwo() { /** @@ -66,7 +65,7 @@ public double process(double a, double b) { } }; /** - * 定义矩阵对应元素的乘法操作 + * 锟斤拷锟斤拷锟斤拷锟斤拷应元锟截的乘凤拷锟斤拷锟斤拷 */ public static OperatorOnTwo multiply = new OperatorOnTwo() { /** @@ -81,7 +80,7 @@ public double process(double a, double b) { }; /** - * 定义矩阵对应元素的减法操作 + * 锟斤拷锟斤拷锟斤拷锟斤拷应元锟截的硷拷锟斤拷锟斤拷锟斤拷 */ public static OperatorOnTwo minus = new OperatorOnTwo() { /** @@ -105,7 +104,7 @@ public static void printMatrix(double[][] matrix) { } /** - * 对矩阵进行180度旋转,是在matrix的副本上复制,不会对原来的矩阵进行修改 + * 锟皆撅拷锟斤拷锟斤拷锟180锟斤拷锟斤拷转,锟斤拷锟斤拷matrix锟侥革拷锟斤拷锟较革拷锟狡o拷锟斤拷锟斤拷锟皆拷锟斤拷木锟斤拷锟斤拷锟斤拷锟睫革拷 * * @param matrix */ @@ -113,7 +112,7 @@ public static double[][] rot180(double[][] matrix) { matrix = cloneMatrix(matrix); int m = matrix.length; int n = matrix[0].length; - // 按列对称进行交换 + // 锟斤拷锟叫对称斤拷锟叫斤拷锟斤拷 for (int i = 0; i < m; i++) { for (int j = 0; j < n / 2; j++) { double tmp = matrix[i][j]; @@ -121,7 +120,7 @@ public static double[][] rot180(double[][] matrix) { matrix[i][n - 1 - j] = tmp; } } - // 按行对称进行交换 + // 锟斤拷锟叫对称斤拷锟叫斤拷锟斤拷 for (int j = 0; j < n; j++) { for (int i = 0; i < m / 2; i++) { double tmp = matrix[i][j]; @@ -135,7 +134,7 @@ public static double[][] rot180(double[][] matrix) { private static Random r = new Random(2); /** - * 随机初始化矩阵 + * 锟斤拷锟斤拷锟绞硷拷锟斤拷锟斤拷锟 * * @param x * @param y @@ -147,7 +146,7 @@ public static double[][] randomMatrix(int x, int y, boolean b) { int tag = 1; for (int i = 0; i < x; i++) { for (int j = 0; j < y; j++) { - // 随机值在[-0.05,0.05)之间,让权重初始化值较小,有利于于避免过拟合 + // 锟斤拷锟街碉拷锟絒-0.05,0.05)之锟戒,锟斤拷权锟截筹拷始锟斤拷值锟斤拷小锟斤拷锟斤拷锟斤拷锟斤拷锟节憋拷锟斤拷锟斤拷锟斤拷 matrix[i][j] = (r.nextDouble() - 0.05) / 10; // matrix[i][j] = tag * 0.5; // if (b) @@ -160,7 +159,7 @@ public static double[][] randomMatrix(int x, int y, boolean b) { } /** - * 随机初始化一维向量 + * 锟斤拷锟斤拷锟绞硷拷锟揭晃拷锟斤拷锟 * * @param len * @return @@ -175,7 +174,7 @@ public static double[] randomArray(int len) { } /** - * 随机排列的抽样,随机抽取batchSize个[0,size)的书 + * 锟斤拷锟斤拷锟斤拷械某锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷取batchSize锟斤拷[0,size)锟斤拷锟斤拷 * * @param size * @param batchSize @@ -194,7 +193,7 @@ public static int[] randomPerm(int size, int batchSize) { } /** - * 复制矩阵 + * 锟斤拷锟狡撅拷锟斤拷 * * @param matrix * @return @@ -214,7 +213,7 @@ public static double[][] cloneMatrix(final double[][] matrix) { } /** - * 对单个矩阵进行操作 + * 锟皆碉拷锟斤拷锟斤拷锟斤拷锟斤拷胁锟斤拷锟 * * @param ma * @param operator @@ -233,15 +232,15 @@ public static double[][] matrixOp(final double[][] ma, Operator operator) { } /** - * 两个维度相同的矩阵对应元素操作,得到的结果方法mb中,即mb[i][j] = (op_a + * 锟斤拷锟斤拷维锟斤拷锟斤拷同锟侥撅拷锟斤拷锟接υ拷夭锟斤拷锟,锟矫碉拷锟侥斤拷锟斤拷锟斤拷锟絤b锟叫o拷锟斤拷mb[i][j] = (op_a * ma[i][j]) op (op_b mb[i][j]) * * @param ma * @param mb * @param operatorB - * 在第mb矩阵上的操作 + * 锟节碉拷mb锟斤拷锟斤拷锟较的诧拷锟斤拷 * @param operatorA - * 在ma矩阵元素上的操作 + * 锟斤拷ma锟斤拷锟斤拷元锟斤拷锟较的诧拷锟斤拷 * @return * */ @@ -251,7 +250,7 @@ public static double[][] matrixOp(final double[][] ma, final double[][] mb, final int m = ma.length; int n = ma[0].length; if (m != mb.length || n != mb[0].length) - throw new RuntimeException("两个矩阵大小不一致 ma.length:" + ma.length + throw new RuntimeException("锟斤拷锟斤拷锟斤拷锟斤拷锟叫★拷锟揭伙拷锟 ma.length:" + ma.length + " mb.length:" + mb.length); for (int i = 0; i < m; i++) { @@ -269,7 +268,7 @@ public static double[][] matrixOp(final double[][] ma, final double[][] mb, } /** - * 克罗内克积,对矩阵进行扩展 + * 锟斤拷锟斤拷锟节克伙拷,锟皆撅拷锟斤拷锟斤拷锟斤拷锟秸 * * @param matrix * @param scale @@ -293,7 +292,7 @@ public static double[][] kronecker(final double[][] matrix, final Size scale) { } /** - * 对矩阵进行均值缩小 + * 锟皆撅拷锟斤拷锟斤拷芯锟街碉拷锟叫 * * @param matrix * @param scaleSize @@ -307,7 +306,7 @@ public static double[][] scaleMatrix(final double[][] matrix, final int sn = n / scale.y; final double[][] outMatrix = new double[sm][sn]; if (sm * scale.x != m || sn * scale.y != n) - throw new RuntimeException("scale不能整除matrix"); + throw new RuntimeException("scale锟斤拷锟斤拷锟斤拷锟斤拷matrix"); final int size = scale.x * scale.y; for (int i = 0; i < sm; i++) { for (int j = 0; j < sn; j++) { @@ -324,7 +323,7 @@ public static double[][] scaleMatrix(final double[][] matrix, } /** - * 计算full模式的卷积 + * 锟斤拷锟斤拷full模式锟侥撅拷锟 * * @param matrix * @param kernel @@ -336,7 +335,7 @@ public static double[][] convnFull(double[][] matrix, int n = matrix[0].length; final int km = kernel.length; final int kn = kernel[0].length; - // 扩展矩阵 + // 锟斤拷展锟斤拷锟斤拷 final double[][] extendMatrix = new double[m + 2 * (km - 1)][n + 2 * (kn - 1)]; for (int i = 0; i < m; i++) { @@ -347,7 +346,7 @@ public static double[][] convnFull(double[][] matrix, } /** - * 计算valid模式的卷积 + * 锟斤拷锟斤拷valid模式锟侥撅拷锟 * * @param matrix * @param kernel @@ -360,11 +359,11 @@ public static double[][] convnValid(final double[][] matrix, int n = matrix[0].length; final int km = kernel.length; final int kn = kernel[0].length; - // 需要做卷积的列数 + // 锟斤拷要锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟 int kns = n - kn + 1; - // 需要做卷积的行数 + // 锟斤拷要锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟 final int kms = m - km + 1; - // 结果矩阵 + // 锟斤拷锟斤拷锟斤拷锟 final double[][] outMatrix = new double[kms][kns]; for (int i = 0; i < kms; i++) { @@ -383,7 +382,7 @@ public static double[][] convnValid(final double[][] matrix, } /** - * 三维矩阵的卷积,这里要求两个矩阵的一维相同 + * 锟斤拷维锟斤拷锟斤拷木锟斤拷,锟斤拷锟斤拷要锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟揭晃拷锟酵 * * @param matrix * @param kernel @@ -401,8 +400,8 @@ public static double[][] convnValid(final double[][][][] matrix, int kns = n - kn + 1; int khs = h - kh + 1; if (matrix.length != kernel.length) - throw new RuntimeException("矩阵与卷积核在第一维上不同"); - // 结果矩阵 + throw new RuntimeException("锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟节碉拷一维锟较诧拷同"); + // 锟斤拷锟斤拷锟斤拷锟 final double[][][] outMatrix = new double[kms][kns][khs]; for (int i = 0; i < kms; i++) { for (int j = 0; j < kns; j++) @@ -426,10 +425,10 @@ public static double sigmod(double x) { } /** - * 对矩阵元素求和 + * 锟皆撅拷锟斤拷元锟斤拷锟斤拷锟 * * @param error - * @return 注意这个求和很可能会溢出 + * @return 注锟斤拷锟斤拷锟斤拷锟酵很匡拷锟杰伙拷锟斤拷锟 */ public static double sum(double[][] error) { @@ -445,7 +444,7 @@ public static double sum(double[][] error) { } /** - * 对errors[...][j]元素求和 + * 锟斤拷errors[...][j]元锟斤拷锟斤拷锟 * * @param errors * @param j @@ -482,7 +481,7 @@ public static int binaryArray2int(double[] array) { } /** - * 测试卷积,测试结果:4核下并发并行的卷积提高不到2倍 + * 锟斤拷锟皆撅拷锟,锟斤拷锟皆斤拷锟斤拷锟4锟斤拷锟铰诧拷锟斤拷锟斤拷锟叫的撅拷锟斤拷锟竭诧拷锟斤拷2锟斤拷 */ private static void testConvn() { int count = 1; @@ -608,7 +607,7 @@ public static void main(String[] args) { } /** - * 取最大的元素的下标 + * 取锟斤拷锟斤拷元锟截碉拷锟铰憋拷 * * @param out * @return diff --git a/src/test/dataset/readme.md b/src/test/dataset/readme.md new file mode 100644 index 0000000..01c8d6d --- /dev/null +++ b/src/test/dataset/readme.md @@ -0,0 +1,3 @@ +The dataset is part of MNIST from kaggle Digit Recognizer competition: +* "train.format" is the train set, which has been binarized. +* "test.format" is the test set, which has been binarized. diff --git a/dataset/test.format b/src/test/dataset/test.format similarity index 100% rename from dataset/test.format rename to src/test/dataset/test.format diff --git a/dataset/train.format b/src/test/dataset/train.format similarity index 100% rename from dataset/train.format rename to src/test/dataset/train.format diff --git a/src/test/java/javacnn/RunCNN.java b/src/test/java/javacnn/RunCNN.java new file mode 100644 index 0000000..cae9051 --- /dev/null +++ b/src/test/java/javacnn/RunCNN.java @@ -0,0 +1,52 @@ +package javacnn; + +import java.io.IOException; + +import javacnn.cnn.CNN; +import javacnn.cnn.CNNLoader; +import javacnn.cnn.Layer; +import javacnn.dataset.Dataset; +import javacnn.dataset.DatasetLoader; +import javacnn.util.ConcurenceRunner; + +public class RunCNN { + + public static void main(String[] args) throws IOException, ClassNotFoundException { + + final ConcurenceRunner concurenceRunner = new ConcurenceRunner(); + + try { + + final CNN.LayerBuilder builder = + new CNN.LayerBuilder() + .addLayer(Layer.buildInputLayer(new Layer.Size(28, 28))) + .addLayer(Layer.buildConvLayer(6, new Layer.Size(5, 5))) + .addLayer(Layer.buildSampLayer(new Layer.Size(2, 2))) + .addLayer(Layer.buildConvLayer(12, new Layer.Size(5, 5))) + .addLayer(Layer.buildSampLayer(new Layer.Size(2, 2))) + .addLayer(Layer.buildOutputLayer(10)); + + final CNN cnn = new CNN(builder, 50, concurenceRunner); + // final CNN cnn = new CNN(builder, 50, new DirectRunner()); + + final String fileName = "src/test/dataset/train.format"; + final Dataset dataset = DatasetLoader.load(fileName, ",", 784); + cnn.train(dataset, 3); + + CNNLoader.saveModel("src/test/model.cnn", cnn); + dataset.clear(); + + /* + final CNN cnn = CNNLoader.loadModel("model.cnn"); + cnn.setRunner(concurenceRunner); + */ + + final Dataset testset = DatasetLoader.load("src/test/dataset/test.format", ",", -1); + cnn.predict(testset, "src/test/dataset/test.predict"); + + } finally { + concurenceRunner.shutdown(); + } + } + +}