From 817601ce7f4c74403056b88aacfeef16d2137b10 Mon Sep 17 00:00:00 2001 From: Sebb Date: Sat, 18 Jan 2025 21:57:24 +0000 Subject: [PATCH] Normalise EOL --- .gitattributes | 2 + .github/workflows/codeql-analysis.yml | 156 +- RELEASE-NOTES.txt | 586 +-- .../commons/vfs2/tasks/ShowFileTask.java | 296 +- commons-vfs2-examples/src/site/xdoc/index.xml | 208 +- .../vfs2/provider/hdfs/HdfsFileObject.java | 626 +-- .../provider/webdav4/Webdav4FileObject.java | 1328 +++--- .../test-data/read-xml-tests/address.xsd | 90 +- .../test-data/read-xml-tests/file1.xml | 36 +- .../test-data/read-xml-tests/file2.xml | 36 +- .../test-data/read-xml-tests/file3-bigger.xml | 2708 ++++++------ .../test-data/read-xml-tests/name-invalid.xml | 50 +- .../read-xml-tests/name-not-well-formed.xml | 48 +- .../read-xml-tests/name-with-xsd-ref.xml | 50 +- .../test-data/read-xml-tests/name.xml | 44 +- .../test-data/read-xml-tests/name.xsd | 84 +- .../test-data/read-xml-tests/person.xml | 76 +- .../test-data/read-xml-tests/person.xsd | 96 +- commons-vfs2-sandbox/src/site/xdoc/index.xml | 94 +- commons-vfs2/pom.xml | 848 ++-- .../vfs2/impl/StandardFileSystemManager.java | 890 ++-- .../vfs2/provider/AbstractFileName.java | 1084 ++--- .../vfs2/provider/AbstractFileObject.java | 3798 ++++++++--------- .../vfs2/provider/DelegateFileObject.java | 848 ++-- .../vfs2/provider/LayeredFileNameParser.java | 248 +- .../commons/vfs2/provider/UriParser.java | 1150 ++--- .../vfs2/provider/ftp/FtpFileObject.java | 1302 +++--- .../provider/http5/Http5FileProvider.java | 750 ++-- .../provider/local/WindowsFileNameParser.java | 286 +- .../vfs2/provider/ram/RamFileData.java | 514 +-- .../vfs2/provider/ram/RamFileSystem.java | 496 +-- .../vfs2/provider/sftp/BytesIdentityInfo.java | 244 +- .../vfs2/provider/sftp/IdentityInfo.java | 322 +- .../sftp/SftpFileSystemConfigBuilder.java | 1646 +++---- commons-vfs2/src/site/xdoc/index.xml | 78 +- .../commons/vfs2/FileSystemOptionsTest.java | 324 +- .../provider/test/FileObjectSortTest.java | 260 +- .../src/test/resources/log4j.properties | 72 +- .../org.apache.ftpserver/users.properties | 86 +- .../test-data/read-xml-tests/address.xsd | 90 +- .../test-data/read-xml-tests/file1.xml | 36 +- .../test-data/read-xml-tests/file2.xml | 36 +- .../test-data/read-xml-tests/file3-bigger.xml | 2708 ++++++------ .../test-data/read-xml-tests/name-invalid.xml | 50 +- .../read-xml-tests/name-not-well-formed.xml | 48 +- .../read-xml-tests/name-with-xsd-ref.xml | 50 +- .../test-data/read-xml-tests/name.xml | 44 +- .../test-data/read-xml-tests/name.xsd | 84 +- .../test-data/read-xml-tests/person.xml | 76 +- .../test-data/read-xml-tests/person.xsd | 96 +- src/changes/release-notes.vm | 268 +- 51 files changed, 12724 insertions(+), 12722 deletions(-) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..db173deb64 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +* text=auto +*.patch -text diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 86248adde1..dd57c39aee 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -1,85 +1,85 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -name: "CodeQL" - -on: - push: - branches: [ master ] - pull_request: - # The branches below must be a subset of the branches above - branches: [ master ] - schedule: - - cron: '33 9 * * 4' - -permissions: - contents: read - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - permissions: - actions: read - contents: read - security-events: write - - strategy: - fail-fast: false - matrix: - language: [ 'java' ] - # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] - # Learn more about CodeQL language support at https://git.io/codeql-language-support - - steps: - - name: Checkout repository +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: "CodeQL" + +on: + push: + branches: [ master ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ master ] + schedule: + - cron: '33 9 * * 4' + +permissions: + contents: read + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'java' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] + # Learn more about CodeQL language support at https://git.io/codeql-language-support + + steps: + - name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false - uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 - with: - path: ~/.m2/repository - key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} - restore-keys: | - ${{ runner.os }}-maven- - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL uses: github/codeql-action/init@b6a472f63d85b9c78a3ac5e89422239fc15e9b3c # 3.28.1 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild uses: github/codeql-action/autobuild@b6a472f63d85b9c78a3ac5e89422239fc15e9b3c # 3.28.1 - - # ℹī¸ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl - - # ✏ī¸ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language - - #- run: | - # make bootstrap - # make release - - - name: Perform CodeQL Analysis + + # ℹī¸ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # ✏ī¸ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@b6a472f63d85b9c78a3ac5e89422239fc15e9b3c # 3.28.1 diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index c9222125ae..f0475b8678 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -1,296 +1,296 @@ -Apache Commons VFS Project 2.10.0 -RELEASE NOTES - -The Apache Commons VFS Project team is pleased to announce the release of Apache Commons VFS Project 2.10.0. - -Apache Commons VFS is a Virtual File System library. - -Maintenance release. Requires Java 8 or above. - -Changes in this version ------------------------ - -New features ------------- - -* VFS-848: Config option for trailing slash in webdav URI #425. Thanks to beise, Gary Gregory. -* Split out Apache Ant Tasks into its own Maven module commons-vfs2-ant. Thanks to Gary Gregory. -* VFS-851: Split out HDFS provider into its own Maven module commons-vfs2-hdfs. Thanks to Gary Gregory. -* Generate JPMS module info files when building on Java 11 or greater, except for commons-vfs2-hdfs due to Hadoop libraries' overlapping packages. Thanks to Gary Gregory. -* Add Visual Studio Code files to gitignore #205. Thanks to Seth Falco. -* Add DefaultFileMonitor.setDelay(Duration), getDelayDuration() and deprecate setDelay(long), getDelay(). Thanks to Gary Gregory. -* DefaultFileMonitor implements AutoCloseable. Thanks to Gary Gregory. -* Add FalseFileFilter.INSTANCE and deprecate FalseFileFilter.FALSE. Thanks to Gary Gregory. -* Add TrueFileFilter.INSTANCE and deprecate TrueFileFilter.TRUE. Thanks to Gary Gregory. -* FileSystemOptions implements Comparable. Thanks to Gary Gregory. -* Add RandomAccessMode.from(AccessMode) and toAccessModes(). Thanks to Gary Gregory. -* Extract the layer separator character constant into LayeredFileName.LAYER_SEPARATOR. Thanks to Gary Gregory. -* Add github/codeql-action. -* VFS-821: Deprecate FileSelector#traverseDescendents in favor of traverseDescendants. Thanks to Marc Wrobel, Gary Gregory. -* VFS-821: Add active port range configuration for FTP client factory #318. Thanks to Maksym Perevertov, Gary Gregory. -* VFS-833: Make constructor FileSystemOptions(Map) public. Thanks to Kannan Ramamoorthy, Bernd Eckenfels, Gary Gregory. -* Add a BOM POM commons-vfs2-bom. Thanks to Gary Gregory. -* Add FileSystemConfigBuilder.getParamOrDefault(FileSystemOptions, String, T). Thanks to Gary Gregory. - -Fixed Bugs: -* VFS-854: Avoid debug-logging URL credentials. Thanks to Andrey Turbanov. -* VFS-853: Double wrapped weak FileListener can lose change notification with DelegateFileObject. Thanks to Bernd Eckenfels. -* Replace package.html with package-info.java #206. Thanks to Seth Falco. -* VFS-807: LocalFile.doGetOutputStream(boolean) for an existing file no longer truncates the file. Thanks to Gary Gregory, L. -* Update the Javadoc link to not lead to 404. #218. Thanks to wodencafe. -* VFS-810: Percent encoded backslashes in authority of URLs aren't allowed for WebDav. Thanks to Jan Aelbrecht, Gary Gregory. -* VFS-793: GenericFileName.getURI() returns invalid URI. Thanks to Vitali Nashkevich, Gary Gregory. -* Fix typos in error messages. Thanks to Gary Gregory. -* LocalFile: Fix exception message "Unknown message with code" and use an actual message code. Thanks to Gary Gregory. -* VFS-778: SFTP channel isn't returned to the pool when SftpFileObject.doGetOutputStream throws an exception. #215. Thanks to zhouwenqing, Gary Gregory. -* Fix OSGi "Unused Import-Package instructions". Thanks to Gary Gregory. -* VFS-813: NullPointerException needs a better message in SftpClientFactory when connect with private key. Thanks to Andrey Turbanov, Gary Gregory. -* VFS-811: Javadoc API links are broken in the commons-vfs project site #227. Thanks to Woonsan Ko, Gary Gregory. -* VFS-812: Don't throw FileSystemException when closing file content output stream using a BufferedOutputStream #228. Thanks to XenoAmess, Gary Gregory. -* VFS-814: FtpFileObject: re-fetch MDTM after refresh #238. Thanks to Luke Wood, Gary Gregory. -* Simplify conditions and avoid extra checks #253. Thanks to Arturo Bernal. -* Refactor AbstractFileObject#getOutputStream() #151. Thanks to Boris Petrov, Gary Gregory. -* VFS-770: FileSystemManager.createFileSystem(FileObject) fails on Gzip files. #92. Thanks to Thomas BELOT, PeterAlfredLee, Gary Gregory. -* Simplify/remove redundant operations. #258. Thanks to Arturo Bernal. -* SFTP: Memory leak because AbstractFileProvider#findFileSystem. Thanks to Tobias Gierke, Gary Gregory. -* Fix typos #275, #276, #277. Thanks to Marc Wrobel. -* Fix links in Javadoc and documentations #284. Thanks to Marc Wrobel. -* [SFTP] Handle the case where a user does not have any groups #280. Thanks to Mark van der Walle, Gary Gregory. -* The dependency hadoop-hdfs-client is not set as optional #291. Thanks to ymenager. -* AbstractFileObject uses the wrong exception for "cause" #316. Thanks to Boris Petrov. -* JUnit5 assertThrows SftpFileSystemGroupsTests #323. Thanks to John Patrick. -* VFS-825: Fix for GZip input and output stream results in StackOverflowError #322. Thanks to Anthony Goubard. -* MonitorInputStream.read(byte[], int, int) and read() should be synchronized like the superclass BufferedInputStream. Thanks to Gary Gregory. -* VFS-683: Class loader thread safety #367. Thanks to Daryl Odnert, Otto Fowler, Bernd Eckenfels, Dave MacDonald, Ivan Bella, Gary Gregory. -* VFS-832: Sftp channel not put back in doGetInputStream #370. Thanks to Wangerry, Gary Gregory. -* [StepSecurity] ci: Harden GitHub Actions #401. Thanks to step-security-bot, Gary Gregory. -* VFS-846: Resolve a FileName to correct FileType #424. Thanks to beise, Gary Gregory. -* VFS-844: Prevent that source files urlString is twice URIEncoded #423. Thanks to beise, Gary Gregory. -* VFS-843: Close the HttpConnection after consuming the entire HttpEntity #421. Thanks to beise, Gary Gregory. -* VFS-841: Copy the Main class for testing with Jackrabbit Standalone Components instead of reusing #409. Thanks to Woonsan Ko, Gary Gregory. -* VFS-849: HttpConnection resources not properly cleaned up in webdav request #428. Thanks to beise, Gary Gregory. -* Don't use deprecated methods in org.apache.commons.vfs2.provider.ftp.FtpClientFactory. Thanks to Gary Gregory. -* Reduce deprecated calls in org.apache.commons.vfs2.provider.http5. Thanks to Gary Gregory. -* DelegatingFileSystemOptionsBuilder.setConfigClass[es](FileSystemOptions, String, String, Class) now throw the more general ReflectiveOperationException instead of 2 subclasses. Thanks to Gary Gregory. -* VFS-524: A URI with an IPv6 address can't be parsed out correctly #438. Thanks to Alex, Fedor Yudanov, Gary Gregory. -* Port assertions to JUnit 5 APIs. Thanks to Gary Gregory. -* Scheme "http" now uses Apache HttpClient 5 instead of HttpClient 3. Thanks to Gary Gregory. -* Scheme "https" now uses Apache HttpClient 5 instead of HttpClient 3. Thanks to Gary Gregory. -* Deprecate package org.apache.commons.vfs2.provider.http in favor of org.apache.commons.vfs2.provider.http5. Thanks to Gary Gregory. -* Deprecate package org.apache.commons.vfs2.provider.https in favor of org.apache.commons.vfs2.provider.http5s. Thanks to Gary Gregory. -* Deprecate package org.apache.commons.vfs2.provider.http4 in favor of org.apache.commons.vfs2.provider.http5. Thanks to Gary Gregory. -* Deprecate package org.apache.commons.vfs2.provider.http4s in favor of org.apache.commons.vfs2.provider.http5s. Thanks to Gary Gregory. -* Support URLencoding during normalization #396. Thanks to Arnout Engelen, Gary Gregory. -* Add some documentation to make the unit tests easier to follow #556. Thanks to Arnout Engelen, Gary Gregory. -* Fix or address PMD warnings UnnecessaryReturn, UnusedLocalVariable, UnnecessaryFullyQualifiedName, UnnecessaryImport, and so on. Thanks to Gary Gregory. -* Simplify UriParser #558. Thanks to Arnout Engelen. -* ZipFileSystemConfigBuilder.getCharset(FileSystemOptions) returns UTF-8 instead of null when absent. Thanks to Gary Gregory. -* org.apache.commons.vfs2.provider.http.HttpFileObject.doListChildren() now throws UnsupportedOperationException instead of Exception. Thanks to Gary Gregory. -* Pick up exec-maven-plugin version from parent POM. Thanks to Gary Gregory. -* Fixed commons-vfs2-sandbox module not compiling due to missing imports and library #634. Thanks to Anthony Goubard. -* FtpFileObject.getChildren() should throw org.apache.commons.vfs2.FileNotFoundException instead of java.io.FileNotFoundException #638. Thanks to Marek Sunda, Gary Gregory, Arnout Engelen. - -Changes -------- - -* Bump org.apache.commons:commons-parent from 52 to 78 #497, #588, #592, #600, #608, #615, #623. Thanks to Dependabot, Gary Gregory. -* Bump actions/cache and others. Thanks to Dependabot, Gary Gregory. -* Bump actions/checkout #217, #220, #245, #315, and others. Thanks to Dependabot, Gary Gregory. -* Bump actions/setup-java #324, and others. Thanks to Gary Gregory, Dependabot. -* Bump actions/upload-artifact from #327, and others. Thanks to Dependabot. -* Bump jakarta.mail from 1.6.7 to 2.0.1 #200. Thanks to Dependabot. -* Bump commons.animal-sniffer.version from 1.19 to 1.21. Thanks to Gary Gregory. -* Bump com.puppycrawl.tools:checkstyle from 8.44 to 9.3 #211. Thanks to Gary Gregory. -* Bump com.github.spotbugs:spotbugs from 4.3.0 to 4.7.3 #216, #269, #319. Thanks to Dependabot, Gary Gregory. -* Bump spotbugs-maven-plugin from 4.3.0 to 4.7.3.0, #229, #236. #264, #282, #331, #333. Thanks to Gary Gregory, Dependabot. -* Bump org.apache.jackrabbit:jackrabbit-standalone-components from 2.21.7 to 2.20.16, 2.21.x is beta only. Thanks to Dependabot, Gary Gregory. -* Bump org.apache.httpcomponents.client5:httpclient5 from 5.1 to 5.4.1 #561, #602, #2778. Thanks to Gary Gregory, Dependabot. -* Bump org.apache.httpcomponents.core5:httpcore5 from 5.1.5 to 5.3.1 #369, #399, #429, #447, #559, #597, #624. Thanks to Dependabot, Gary Gregory. -* Bump org.apache.mina:mina-core from 2.1.4 to 2.1.8. Thanks to Gary Gregory, Dependabot. -* Bump maven-pmd-plugin from 3.14.0 to 3.19.0 #223, #294, #304. Thanks to Dependabot, Gary Gregory. -* Bump net.sourceforge.pmd:pmd-* from 6.36.0 to 6.53.0 #208, #247, #256, #261, #266, #270, #283, #339, #361. Thanks to Dependabot, Gary Gregory. -* Bump org.mockito:mockito-core from 3.11.2 to 4.11.0 #263, #292, #308, #337, #355, #359. Thanks to Gary Gregory, Dependabot. -* Bump maven-javadoc-plugin from 3.3.0 to 3.4.1, #293. Thanks to Gary Gregory, Dependabot. -* Bump biz.aQute.bnd:biz.aQute.bndlib from 5.3.0 to 6.3.1. Thanks to Gary Gregory. -* Bump commons.japicmp.version from 0.15.3 to 0.16.0. Thanks to Gary Gregory. -* Replace JUnit 4.13.2 with 5.9.1 #281, #306. Thanks to Gary Gregory, John Patrick, Dependabot. -* Bump org.apache.httpcomponents:httpcore-nio from 4.4.14 to 4.4.16, #341. Thanks to Gary Gregory, Dependabot. -* Bump Apache Log4j 2.14.1 to 2.24.3 [Tests] #226, #230, #305, #378, #448, #461, #487, #499, #598, #610, #635, #642. Thanks to Gary Gregory, Dependabot. -* Bump ftpserver-core from 1.1.1 to 1.1.2 #235. Thanks to XenoAmess. -* Bump hadoop.version from 3.3.1 to 3.4.1 #246, #262, #290, #386, #402, #620. Thanks to Dependabot. -* Bump slf4j.version from 1.7.26 to 2.0.16 #484, #486, #524, #575, #580, #585. Thanks to Dependabot. -* Bump org.ow2.asm:asm from 9.2 to 9.4. Thanks to Gary Gregory. -* Bump commons.jacoco.version from 0.8.7 to 0.8.8. Thanks to Gary Gregory. -* Bump commons.surefire.version from 3.0.0-M5 to 3.0.0-M7. Thanks to Gary Gregory. -* Bump Apache Commons BCEL from 6.5.0 to 6.10.0 #346, #451, #522, #569. Thanks to Gary Gregory, Dependabot. -* Bump maven-checkstyle-plugin from 3.1.2 to 3.2.0 #321 Thanks to Dependabot. -* Bump commons-compress from 1.21 to 1.27.1 #329, #385, $498, #535, #579, #590. Thanks to Dependabot, Gary Gregory. -* Bump commons-net:commons-net from 3.8.0 to 3.11.1 #546, #548. Thanks to Gary Gregory, Dependabot. -* Bump httpclient from 4.5.13 to 4.5.14 #344. Thanks to Dependabot. -* Bump commons-io:commons-io from 2.11.0 to 2.18.0 #515, #601, #633. Thanks to Gary Gregory. -* Bump commons-codec:commons-codec from 1.15 to 1.17.1 #480, #530, #567. Thanks to Gary Gregory. -* Bump org.apache.commons:commons-lang3 from 3.12.0 to 3.17.0 #568, #577, #594. Thanks to Gary Gregory. -* Bump org.codehaus.mojo:exec-maven-plugin from 3.1.0 to 3.4.0 #445, #536, #576. Thanks to Dependabot. -* Bump commons-logging:commons-logging from 1.2 to 1.3.4, #531, #563, #589. Thanks to Gary Gregory. -* Bump org.codehaus.mojo:exec-maven-plugin from 3.1.1 to 3.4.1 #494, #586. Thanks to Gary Gregory. -* Bump org.apache.commons:commons-collections4 from 4.4 to 4.5.0-M3 #643. Thanks to Gary Gregory. -* Bump ant:ant 1.6.5 to org.apache.ant:ant 1.10.14. Thanks to Gary Gregory. -* Bump org.apache.mina:mina-core from 2.1.8 to 2.1.9. Thanks to Gary Gregory. - - -Historical list of changes: https://commons.apache.org/proper/commons-vfs/changes-report.html - -For complete information on Apache Commons VFS Project, including instructions on how to submit bug reports, -patches, or suggestions for improvement, see the Apache Commons VFS Project website: - -https://commons.apache.org/proper/commons-vfs/ - -Download page: https://commons.apache.org/proper/commons-vfs/download_vfs.cgi - ------------------------------------------------------------------------------ - -Apache Commons VFS Project 2.10.0 -RELEASE NOTES - -The Apache Commons VFS Project team is pleased to announce the release of Apache Commons VFS Project 2.10.0. - -Apache Commons VFS is a Virtual File System library. - -Maintenance release. Requires Java 8 or above. - -Changes in this version ------------------------ - -New features ------------- - -* VFS-848: Config option for trailing slash in webdav URI #425. Thanks to beise, Gary Gregory. -* Split out Apache Ant Tasks into its own Maven module commons-vfs2-ant. Thanks to Gary Gregory. -* VFS-851: Split out HDFS provider into its own Maven module commons-vfs2-hdfs. Thanks to Gary Gregory. -* Generate JPMS module info files when building on Java 11 or greater, except for commons-vfs2-hdfs due to Hadoop libraries' overlapping packages. Thanks to Gary Gregory. -* Add Visual Studio Code files to gitignore #205. Thanks to Seth Falco. -* Add DefaultFileMonitor.setDelay(Duration), getDelayDuration() and deprecate setDelay(long), getDelay(). Thanks to Gary Gregory. -* DefaultFileMonitor implements AutoCloseable. Thanks to Gary Gregory. -* Add FalseFileFilter.INSTANCE and deprecate FalseFileFilter.FALSE. Thanks to Gary Gregory. -* Add TrueFileFilter.INSTANCE and deprecate TrueFileFilter.TRUE. Thanks to Gary Gregory. -* FileSystemOptions implements Comparable. Thanks to Gary Gregory. -* Add RandomAccessMode.from(AccessMode) and toAccessModes(). Thanks to Gary Gregory. -* Extract the layer separator character constant into LayeredFileName.LAYER_SEPARATOR. Thanks to Gary Gregory. -* Add github/codeql-action. -* VFS-821: Deprecate FileSelector#traverseDescendents in favor of traverseDescendants. Thanks to Marc Wrobel, Gary Gregory. -* VFS-821: Add active port range configuration for FTP client factory #318. Thanks to Maksym Perevertov, Gary Gregory. -* VFS-833: Make constructor FileSystemOptions(Map) public. Thanks to Kannan Ramamoorthy, Bernd Eckenfels, Gary Gregory. -* Add a BOM POM commons-vfs2-bom. Thanks to Gary Gregory. - -Fixed Bugs: -* VFS-854: Avoid debug-logging URL credentials. Thanks to Andrey Turbanov. -* VFS-853: Double wrapped weak FileListener can lose change notification with DelegateFileObject. Thanks to Bernd Eckenfels. -* Replace package.html with package-info.java #206. Thanks to Seth Falco. -* VFS-807: LocalFile.doGetOutputStream(boolean) for an existing file no longer truncates the file. Thanks to Gary Gregory, L. -* Update the Javadoc link to not lead to 404. #218. Thanks to wodencafe. -* VFS-810: Percent encoded backslashes in authority of URLs aren't allowed for WebDav. Thanks to Jan Aelbrecht, Gary Gregory. -* VFS-793: GenericFileName.getURI() returns invalid URI. Thanks to Vitali Nashkevich, Gary Gregory. -* Fix typos in error messages. Thanks to Gary Gregory. -* LocalFile: Fix exception message "Unknown message with code" and use an actual message code. Thanks to Gary Gregory. -* VFS-778: SFTP channel isn't returned to the pool when SftpFileObject.doGetOutputStream throws an exception. #215. Thanks to zhouwenqing, Gary Gregory. -* Fix OSGi "Unused Import-Package instructions". Thanks to Gary Gregory. -* VFS-813: NullPointerException needs a better message in SftpClientFactory when connect with private key. Thanks to Andrey Turbanov, Gary Gregory. -* VFS-811: Javadoc API links are broken in the commons-vfs project site #227. Thanks to Woonsan Ko, Gary Gregory. -* VFS-812: Don't throw FileSystemException when closing file content output stream using a BufferedOutputStream #228. Thanks to XenoAmess, Gary Gregory. -* VFS-814: FtpFileObject: re-fetch MDTM after refresh #238. Thanks to Luke Wood, Gary Gregory. -* Simplify conditions and avoid extra checks #253. Thanks to Arturo Bernal. -* Refactor AbstractFileObject#getOutputStream() #151. Thanks to Boris Petrov, Gary Gregory. -* VFS-770: FileSystemManager.createFileSystem(FileObject) fails on Gzip files. #92. Thanks to Thomas BELOT, PeterAlfredLee, Gary Gregory. -* Simplify/remove redundant operations. #258. Thanks to Arturo Bernal. -* SFTP: Memory leak because AbstractFileProvider#findFileSystem. Thanks to Tobias Gierke, Gary Gregory. -* Fix typos #275, #276, #277. Thanks to Marc Wrobel. -* Fix links in Javadoc and documentations #284. Thanks to Marc Wrobel. -* [SFTP] Handle the case where a user does not have any groups #280. Thanks to Mark van der Walle, Gary Gregory. -* The dependency hadoop-hdfs-client is not set as optional #291. Thanks to ymenager. -* AbstractFileObject uses the wrong exception for "cause" #316. Thanks to Boris Petrov. -* JUnit5 assertThrows SftpFileSystemGroupsTests #323. Thanks to John Patrick. -* VFS-825: Fix for GZip input and output stream results in StackOverflowError #322. Thanks to Anthony Goubard. -* MonitorInputStream.read(byte[], int, int) and read() should be synchronized like the superclass BufferedInputStream. Thanks to Gary Gregory. -* VFS-683: Class loader thread safety #367. Thanks to Daryl Odnert, Otto Fowler, Bernd Eckenfels, Dave MacDonald, Ivan Bella, Gary Gregory. -* VFS-832: Sftp channel not put back in doGetInputStream #370. Thanks to Wangerry, Gary Gregory. -* [StepSecurity] ci: Harden GitHub Actions #401. Thanks to step-security-bot, Gary Gregory. -* VFS-846: Resolve a FileName to correct FileType #424. Thanks to beise, Gary Gregory. -* VFS-844: Prevent that source files urlString is twice URIEncoded #423. Thanks to beise, Gary Gregory. -* VFS-843: Close the HttpConnection after consuming the entire HttpEntity #421. Thanks to beise, Gary Gregory. -* VFS-841: Copy the Main class for testing with Jackrabbit Standalone Components instead of reusing #409. Thanks to Woonsan Ko, Gary Gregory. -* VFS-849: HttpConnection resources not properly cleaned up in webdav request #428. Thanks to beise, Gary Gregory. -* Don't use deprecated methods in org.apache.commons.vfs2.provider.ftp.FtpClientFactory. Thanks to Gary Gregory. -* Reduce deprecated calls in org.apache.commons.vfs2.provider.http5. Thanks to Gary Gregory. -* DelegatingFileSystemOptionsBuilder.setConfigClass[es](FileSystemOptions, String, String, Class) now throw the more general ReflectiveOperationException instead of 2 subclasses. Thanks to Gary Gregory. -* VFS-524: A URI with an IPv6 address can't be parsed out correctly #438. Thanks to Alex, Fedor Yudanov, Gary Gregory. -* Port assertions to JUnit 5 APIs. Thanks to Gary Gregory. -* Scheme "http" now uses Apache HttpClient 5 instead of HttpClient 3. Thanks to Gary Gregory. -* Scheme "https" now uses Apache HttpClient 5 instead of HttpClient 3. Thanks to Gary Gregory. -* Deprecate package org.apache.commons.vfs2.provider.http in favor of org.apache.commons.vfs2.provider.http5. Thanks to Gary Gregory. -* Deprecate package org.apache.commons.vfs2.provider.https in favor of org.apache.commons.vfs2.provider.http5s. Thanks to Gary Gregory. -* Deprecate package org.apache.commons.vfs2.provider.http4 in favor of org.apache.commons.vfs2.provider.http5. Thanks to Gary Gregory. -* Deprecate package org.apache.commons.vfs2.provider.http4s in favor of org.apache.commons.vfs2.provider.http5s. Thanks to Gary Gregory. -* Support URLencoding during normalization #396. Thanks to Arnout Engelen, Gary Gregory. -* Add some documentation to make the unit tests easier to follow #556. Thanks to Arnout Engelen, Gary Gregory. -* Fix or address PMD warnings UnnecessaryReturn, UnusedLocalVariable, UnnecessaryFullyQualifiedName, UnnecessaryImport, and so on. Thanks to Gary Gregory. -* Simplify UriParser #558. Thanks to Arnout Engelen. - -Changes -------- - -* Bump actions/cache and others. Thanks to Dependabot, Gary Gregory. -* Bump actions/checkout #217, #220, #245, #315, and others. Thanks to Dependabot, Gary Gregory. -* Bump actions/setup-java #324, and others. Thanks to Gary Gregory, Dependabot. -* Bump actions/upload-artifact from #327, and others. Thanks to Dependabot. -* Bump jakarta.mail from 1.6.7 to 2.0.1 #200. Thanks to Dependabot. -* Bump commons.animal-sniffer.version from 1.19 to 1.21. Thanks to Gary Gregory. -* Bump com.puppycrawl.tools:checkstyle from 8.44 to 9.3 #211. Thanks to Gary Gregory. -* Bump com.github.spotbugs:spotbugs from 4.3.0 to 4.7.3 #216, #269, #319. Thanks to Dependabot, Gary Gregory. -* Bump spotbugs-maven-plugin from 4.3.0 to 4.7.3.0, #229, #236. #264, #282, #331, #333. Thanks to Gary Gregory, Dependabot. -* Bump org.apache.jackrabbit:jackrabbit-standalone-components from 2.21.7 to 2.20.16, 2.21.x is beta only. Thanks to Dependabot, Gary Gregory. -* Bump org.apache.httpcomponents.client5:httpclient5 from 5.1 to 5.4-beta1 #561. Thanks to Gary Gregory, Dependabot. -* Bump org.apache.httpcomponents.core5:httpcore5 from 5.1.5 to 5.3-beta1 #369, #399, #429, #447, #559. Thanks to Dependabot. -* Bump org.apache.mina:mina-core from 2.1.4 to 2.1.8. Thanks to Gary Gregory, Dependabot. -* Bump maven-pmd-plugin from 3.14.0 to 3.19.0 #223, #294, #304. Thanks to Dependabot, Gary Gregory. -* Bump net.sourceforge.pmd:pmd-* from 6.36.0 to 6.53.0 #208, #247, #256, #261, #266, #270, #283, #339, #361. Thanks to Dependabot, Gary Gregory. -* Bump org.mockito:mockito-core from 3.11.2 to 4.11.0 #263, #292, #308, #337, #355, #359. Thanks to Gary Gregory, Dependabot. -* Bump maven-javadoc-plugin from 3.3.0 to 3.4.1, #293. Thanks to Gary Gregory, Dependabot. -* Bump biz.aQute.bnd:biz.aQute.bndlib from 5.3.0 to 6.3.1. Thanks to Gary Gregory. -* Bump commons.japicmp.version from 0.15.3 to 0.16.0. Thanks to Gary Gregory. -* Replace JUnit 4.13.2 with 5.9.1 #281, #306. Thanks to Gary Gregory, John Patrick, Dependabot. -* Bump org.apache.httpcomponents:httpcore-nio from 4.4.14 to 4.4.16, #341. Thanks to Gary Gregory, Dependabot. -* Bump Apache Log4j 2.14.1 to 2.23.1 [Tests] #226, #230, #305, #378, #448, #461, #487, #499. Thanks to Gary Gregory, Dependabot. -* Bump ftpserver-core from 1.1.1 to 1.1.2 #235. Thanks to XenoAmess. -* Bump hadoop.version from 3.3.1 to 3.3.6 #246, #262, #290, #386, #402. Thanks to Dependabot. -* Bump slf4j.version from 1.7.26 to 2.0.15 #484, #486, #524, #575, #580. Thanks to Dependabot. -* Bump org.apache.commons:commons-parent from 52 to 72 #497. Thanks to Dependabot, Gary Gregory. -* Bump org.ow2.asm:asm from 9.2 to 9.4. Thanks to Gary Gregory. -* Bump commons.jacoco.version from 0.8.7 to 0.8.8. Thanks to Gary Gregory. -* Bump commons.surefire.version from 3.0.0-M5 to 3.0.0-M7. Thanks to Gary Gregory. -* Bump Apache Commons BCEL from 6.5.0 to 6.10.0 #346, #451, #522, #569. Thanks to Gary Gregory, Dependabot. -* Bump maven-checkstyle-plugin from 3.1.2 to 3.2.0 #321 Thanks to Dependabot. -* Bump commons-compress from 1.21 to 1.27.0 #329, #385, $498, #535, #579. Thanks to Dependabot, Gary Gregory. -* Bump commons-net:commons-net from 3.8.0 to 3.11.1 #546, #548. Thanks to Gary Gregory, Dependabot. -* Bump httpclient from 4.5.13 to 4.5.14 #344. Thanks to Dependabot. -* Bump commons-io:commons-io from 2.11.0 to 2.16.1 #515. Thanks to Gary Gregory. -* Bump commons-codec:commons-codec from 1.15 to 1.17.1 #480, #530, #567. Thanks to Gary Gregory. -* Bump org.apache.commons:commons-lang3 from 3.12.0 to 3.16.0 #568, #577. Thanks to Gary Gregory. -* Bump org.codehaus.mojo:exec-maven-plugin from 3.1.0 to 3.4.0 #445, #536, #576. Thanks to Dependabot. -* Bump commons-logging:commons-logging from 1.2 to 1.3.3, #531, #563. Thanks to Gary Gregory. -* Bump org.codehaus.mojo:exec-maven-plugin from 3.1.1 to 3.2.0 #494. Thanks to Gary Gregory. -* Bump org.apache.commons:commons-collections4 from 4.4 to 4.5.0-M2. Thanks to Gary Gregory. -* Bump ant:ant 1.6.5 to org.apache.ant:ant 1.10.14. Thanks to Gary Gregory. - - -Historical list of changes: https://commons.apache.org/proper/commons-vfs/changes-report.html - -For complete information on Apache Commons VFS Project, including instructions on how to submit bug reports, -patches, or suggestions for improvement, see the Apache Commons VFS Project website: - -https://commons.apache.org/proper/commons-vfs/ - -Download page: https://commons.apache.org/proper/commons-vfs/download_vfs.cgi - +Apache Commons VFS Project 2.10.0 +RELEASE NOTES + +The Apache Commons VFS Project team is pleased to announce the release of Apache Commons VFS Project 2.10.0. + +Apache Commons VFS is a Virtual File System library. + +Maintenance release. Requires Java 8 or above. + +Changes in this version +----------------------- + +New features +------------ + +* VFS-848: Config option for trailing slash in webdav URI #425. Thanks to beise, Gary Gregory. +* Split out Apache Ant Tasks into its own Maven module commons-vfs2-ant. Thanks to Gary Gregory. +* VFS-851: Split out HDFS provider into its own Maven module commons-vfs2-hdfs. Thanks to Gary Gregory. +* Generate JPMS module info files when building on Java 11 or greater, except for commons-vfs2-hdfs due to Hadoop libraries' overlapping packages. Thanks to Gary Gregory. +* Add Visual Studio Code files to gitignore #205. Thanks to Seth Falco. +* Add DefaultFileMonitor.setDelay(Duration), getDelayDuration() and deprecate setDelay(long), getDelay(). Thanks to Gary Gregory. +* DefaultFileMonitor implements AutoCloseable. Thanks to Gary Gregory. +* Add FalseFileFilter.INSTANCE and deprecate FalseFileFilter.FALSE. Thanks to Gary Gregory. +* Add TrueFileFilter.INSTANCE and deprecate TrueFileFilter.TRUE. Thanks to Gary Gregory. +* FileSystemOptions implements Comparable. Thanks to Gary Gregory. +* Add RandomAccessMode.from(AccessMode) and toAccessModes(). Thanks to Gary Gregory. +* Extract the layer separator character constant into LayeredFileName.LAYER_SEPARATOR. Thanks to Gary Gregory. +* Add github/codeql-action. +* VFS-821: Deprecate FileSelector#traverseDescendents in favor of traverseDescendants. Thanks to Marc Wrobel, Gary Gregory. +* VFS-821: Add active port range configuration for FTP client factory #318. Thanks to Maksym Perevertov, Gary Gregory. +* VFS-833: Make constructor FileSystemOptions(Map) public. Thanks to Kannan Ramamoorthy, Bernd Eckenfels, Gary Gregory. +* Add a BOM POM commons-vfs2-bom. Thanks to Gary Gregory. +* Add FileSystemConfigBuilder.getParamOrDefault(FileSystemOptions, String, T). Thanks to Gary Gregory. + +Fixed Bugs: +* VFS-854: Avoid debug-logging URL credentials. Thanks to Andrey Turbanov. +* VFS-853: Double wrapped weak FileListener can lose change notification with DelegateFileObject. Thanks to Bernd Eckenfels. +* Replace package.html with package-info.java #206. Thanks to Seth Falco. +* VFS-807: LocalFile.doGetOutputStream(boolean) for an existing file no longer truncates the file. Thanks to Gary Gregory, L. +* Update the Javadoc link to not lead to 404. #218. Thanks to wodencafe. +* VFS-810: Percent encoded backslashes in authority of URLs aren't allowed for WebDav. Thanks to Jan Aelbrecht, Gary Gregory. +* VFS-793: GenericFileName.getURI() returns invalid URI. Thanks to Vitali Nashkevich, Gary Gregory. +* Fix typos in error messages. Thanks to Gary Gregory. +* LocalFile: Fix exception message "Unknown message with code" and use an actual message code. Thanks to Gary Gregory. +* VFS-778: SFTP channel isn't returned to the pool when SftpFileObject.doGetOutputStream throws an exception. #215. Thanks to zhouwenqing, Gary Gregory. +* Fix OSGi "Unused Import-Package instructions". Thanks to Gary Gregory. +* VFS-813: NullPointerException needs a better message in SftpClientFactory when connect with private key. Thanks to Andrey Turbanov, Gary Gregory. +* VFS-811: Javadoc API links are broken in the commons-vfs project site #227. Thanks to Woonsan Ko, Gary Gregory. +* VFS-812: Don't throw FileSystemException when closing file content output stream using a BufferedOutputStream #228. Thanks to XenoAmess, Gary Gregory. +* VFS-814: FtpFileObject: re-fetch MDTM after refresh #238. Thanks to Luke Wood, Gary Gregory. +* Simplify conditions and avoid extra checks #253. Thanks to Arturo Bernal. +* Refactor AbstractFileObject#getOutputStream() #151. Thanks to Boris Petrov, Gary Gregory. +* VFS-770: FileSystemManager.createFileSystem(FileObject) fails on Gzip files. #92. Thanks to Thomas BELOT, PeterAlfredLee, Gary Gregory. +* Simplify/remove redundant operations. #258. Thanks to Arturo Bernal. +* SFTP: Memory leak because AbstractFileProvider#findFileSystem. Thanks to Tobias Gierke, Gary Gregory. +* Fix typos #275, #276, #277. Thanks to Marc Wrobel. +* Fix links in Javadoc and documentations #284. Thanks to Marc Wrobel. +* [SFTP] Handle the case where a user does not have any groups #280. Thanks to Mark van der Walle, Gary Gregory. +* The dependency hadoop-hdfs-client is not set as optional #291. Thanks to ymenager. +* AbstractFileObject uses the wrong exception for "cause" #316. Thanks to Boris Petrov. +* JUnit5 assertThrows SftpFileSystemGroupsTests #323. Thanks to John Patrick. +* VFS-825: Fix for GZip input and output stream results in StackOverflowError #322. Thanks to Anthony Goubard. +* MonitorInputStream.read(byte[], int, int) and read() should be synchronized like the superclass BufferedInputStream. Thanks to Gary Gregory. +* VFS-683: Class loader thread safety #367. Thanks to Daryl Odnert, Otto Fowler, Bernd Eckenfels, Dave MacDonald, Ivan Bella, Gary Gregory. +* VFS-832: Sftp channel not put back in doGetInputStream #370. Thanks to Wangerry, Gary Gregory. +* [StepSecurity] ci: Harden GitHub Actions #401. Thanks to step-security-bot, Gary Gregory. +* VFS-846: Resolve a FileName to correct FileType #424. Thanks to beise, Gary Gregory. +* VFS-844: Prevent that source files urlString is twice URIEncoded #423. Thanks to beise, Gary Gregory. +* VFS-843: Close the HttpConnection after consuming the entire HttpEntity #421. Thanks to beise, Gary Gregory. +* VFS-841: Copy the Main class for testing with Jackrabbit Standalone Components instead of reusing #409. Thanks to Woonsan Ko, Gary Gregory. +* VFS-849: HttpConnection resources not properly cleaned up in webdav request #428. Thanks to beise, Gary Gregory. +* Don't use deprecated methods in org.apache.commons.vfs2.provider.ftp.FtpClientFactory. Thanks to Gary Gregory. +* Reduce deprecated calls in org.apache.commons.vfs2.provider.http5. Thanks to Gary Gregory. +* DelegatingFileSystemOptionsBuilder.setConfigClass[es](FileSystemOptions, String, String, Class) now throw the more general ReflectiveOperationException instead of 2 subclasses. Thanks to Gary Gregory. +* VFS-524: A URI with an IPv6 address can't be parsed out correctly #438. Thanks to Alex, Fedor Yudanov, Gary Gregory. +* Port assertions to JUnit 5 APIs. Thanks to Gary Gregory. +* Scheme "http" now uses Apache HttpClient 5 instead of HttpClient 3. Thanks to Gary Gregory. +* Scheme "https" now uses Apache HttpClient 5 instead of HttpClient 3. Thanks to Gary Gregory. +* Deprecate package org.apache.commons.vfs2.provider.http in favor of org.apache.commons.vfs2.provider.http5. Thanks to Gary Gregory. +* Deprecate package org.apache.commons.vfs2.provider.https in favor of org.apache.commons.vfs2.provider.http5s. Thanks to Gary Gregory. +* Deprecate package org.apache.commons.vfs2.provider.http4 in favor of org.apache.commons.vfs2.provider.http5. Thanks to Gary Gregory. +* Deprecate package org.apache.commons.vfs2.provider.http4s in favor of org.apache.commons.vfs2.provider.http5s. Thanks to Gary Gregory. +* Support URLencoding during normalization #396. Thanks to Arnout Engelen, Gary Gregory. +* Add some documentation to make the unit tests easier to follow #556. Thanks to Arnout Engelen, Gary Gregory. +* Fix or address PMD warnings UnnecessaryReturn, UnusedLocalVariable, UnnecessaryFullyQualifiedName, UnnecessaryImport, and so on. Thanks to Gary Gregory. +* Simplify UriParser #558. Thanks to Arnout Engelen. +* ZipFileSystemConfigBuilder.getCharset(FileSystemOptions) returns UTF-8 instead of null when absent. Thanks to Gary Gregory. +* org.apache.commons.vfs2.provider.http.HttpFileObject.doListChildren() now throws UnsupportedOperationException instead of Exception. Thanks to Gary Gregory. +* Pick up exec-maven-plugin version from parent POM. Thanks to Gary Gregory. +* Fixed commons-vfs2-sandbox module not compiling due to missing imports and library #634. Thanks to Anthony Goubard. +* FtpFileObject.getChildren() should throw org.apache.commons.vfs2.FileNotFoundException instead of java.io.FileNotFoundException #638. Thanks to Marek Sunda, Gary Gregory, Arnout Engelen. + +Changes +------- + +* Bump org.apache.commons:commons-parent from 52 to 78 #497, #588, #592, #600, #608, #615, #623. Thanks to Dependabot, Gary Gregory. +* Bump actions/cache and others. Thanks to Dependabot, Gary Gregory. +* Bump actions/checkout #217, #220, #245, #315, and others. Thanks to Dependabot, Gary Gregory. +* Bump actions/setup-java #324, and others. Thanks to Gary Gregory, Dependabot. +* Bump actions/upload-artifact from #327, and others. Thanks to Dependabot. +* Bump jakarta.mail from 1.6.7 to 2.0.1 #200. Thanks to Dependabot. +* Bump commons.animal-sniffer.version from 1.19 to 1.21. Thanks to Gary Gregory. +* Bump com.puppycrawl.tools:checkstyle from 8.44 to 9.3 #211. Thanks to Gary Gregory. +* Bump com.github.spotbugs:spotbugs from 4.3.0 to 4.7.3 #216, #269, #319. Thanks to Dependabot, Gary Gregory. +* Bump spotbugs-maven-plugin from 4.3.0 to 4.7.3.0, #229, #236. #264, #282, #331, #333. Thanks to Gary Gregory, Dependabot. +* Bump org.apache.jackrabbit:jackrabbit-standalone-components from 2.21.7 to 2.20.16, 2.21.x is beta only. Thanks to Dependabot, Gary Gregory. +* Bump org.apache.httpcomponents.client5:httpclient5 from 5.1 to 5.4.1 #561, #602, #2778. Thanks to Gary Gregory, Dependabot. +* Bump org.apache.httpcomponents.core5:httpcore5 from 5.1.5 to 5.3.1 #369, #399, #429, #447, #559, #597, #624. Thanks to Dependabot, Gary Gregory. +* Bump org.apache.mina:mina-core from 2.1.4 to 2.1.8. Thanks to Gary Gregory, Dependabot. +* Bump maven-pmd-plugin from 3.14.0 to 3.19.0 #223, #294, #304. Thanks to Dependabot, Gary Gregory. +* Bump net.sourceforge.pmd:pmd-* from 6.36.0 to 6.53.0 #208, #247, #256, #261, #266, #270, #283, #339, #361. Thanks to Dependabot, Gary Gregory. +* Bump org.mockito:mockito-core from 3.11.2 to 4.11.0 #263, #292, #308, #337, #355, #359. Thanks to Gary Gregory, Dependabot. +* Bump maven-javadoc-plugin from 3.3.0 to 3.4.1, #293. Thanks to Gary Gregory, Dependabot. +* Bump biz.aQute.bnd:biz.aQute.bndlib from 5.3.0 to 6.3.1. Thanks to Gary Gregory. +* Bump commons.japicmp.version from 0.15.3 to 0.16.0. Thanks to Gary Gregory. +* Replace JUnit 4.13.2 with 5.9.1 #281, #306. Thanks to Gary Gregory, John Patrick, Dependabot. +* Bump org.apache.httpcomponents:httpcore-nio from 4.4.14 to 4.4.16, #341. Thanks to Gary Gregory, Dependabot. +* Bump Apache Log4j 2.14.1 to 2.24.3 [Tests] #226, #230, #305, #378, #448, #461, #487, #499, #598, #610, #635, #642. Thanks to Gary Gregory, Dependabot. +* Bump ftpserver-core from 1.1.1 to 1.1.2 #235. Thanks to XenoAmess. +* Bump hadoop.version from 3.3.1 to 3.4.1 #246, #262, #290, #386, #402, #620. Thanks to Dependabot. +* Bump slf4j.version from 1.7.26 to 2.0.16 #484, #486, #524, #575, #580, #585. Thanks to Dependabot. +* Bump org.ow2.asm:asm from 9.2 to 9.4. Thanks to Gary Gregory. +* Bump commons.jacoco.version from 0.8.7 to 0.8.8. Thanks to Gary Gregory. +* Bump commons.surefire.version from 3.0.0-M5 to 3.0.0-M7. Thanks to Gary Gregory. +* Bump Apache Commons BCEL from 6.5.0 to 6.10.0 #346, #451, #522, #569. Thanks to Gary Gregory, Dependabot. +* Bump maven-checkstyle-plugin from 3.1.2 to 3.2.0 #321 Thanks to Dependabot. +* Bump commons-compress from 1.21 to 1.27.1 #329, #385, $498, #535, #579, #590. Thanks to Dependabot, Gary Gregory. +* Bump commons-net:commons-net from 3.8.0 to 3.11.1 #546, #548. Thanks to Gary Gregory, Dependabot. +* Bump httpclient from 4.5.13 to 4.5.14 #344. Thanks to Dependabot. +* Bump commons-io:commons-io from 2.11.0 to 2.18.0 #515, #601, #633. Thanks to Gary Gregory. +* Bump commons-codec:commons-codec from 1.15 to 1.17.1 #480, #530, #567. Thanks to Gary Gregory. +* Bump org.apache.commons:commons-lang3 from 3.12.0 to 3.17.0 #568, #577, #594. Thanks to Gary Gregory. +* Bump org.codehaus.mojo:exec-maven-plugin from 3.1.0 to 3.4.0 #445, #536, #576. Thanks to Dependabot. +* Bump commons-logging:commons-logging from 1.2 to 1.3.4, #531, #563, #589. Thanks to Gary Gregory. +* Bump org.codehaus.mojo:exec-maven-plugin from 3.1.1 to 3.4.1 #494, #586. Thanks to Gary Gregory. +* Bump org.apache.commons:commons-collections4 from 4.4 to 4.5.0-M3 #643. Thanks to Gary Gregory. +* Bump ant:ant 1.6.5 to org.apache.ant:ant 1.10.14. Thanks to Gary Gregory. +* Bump org.apache.mina:mina-core from 2.1.8 to 2.1.9. Thanks to Gary Gregory. + + +Historical list of changes: https://commons.apache.org/proper/commons-vfs/changes-report.html + +For complete information on Apache Commons VFS Project, including instructions on how to submit bug reports, +patches, or suggestions for improvement, see the Apache Commons VFS Project website: + +https://commons.apache.org/proper/commons-vfs/ + +Download page: https://commons.apache.org/proper/commons-vfs/download_vfs.cgi + +----------------------------------------------------------------------------- + +Apache Commons VFS Project 2.10.0 +RELEASE NOTES + +The Apache Commons VFS Project team is pleased to announce the release of Apache Commons VFS Project 2.10.0. + +Apache Commons VFS is a Virtual File System library. + +Maintenance release. Requires Java 8 or above. + +Changes in this version +----------------------- + +New features +------------ + +* VFS-848: Config option for trailing slash in webdav URI #425. Thanks to beise, Gary Gregory. +* Split out Apache Ant Tasks into its own Maven module commons-vfs2-ant. Thanks to Gary Gregory. +* VFS-851: Split out HDFS provider into its own Maven module commons-vfs2-hdfs. Thanks to Gary Gregory. +* Generate JPMS module info files when building on Java 11 or greater, except for commons-vfs2-hdfs due to Hadoop libraries' overlapping packages. Thanks to Gary Gregory. +* Add Visual Studio Code files to gitignore #205. Thanks to Seth Falco. +* Add DefaultFileMonitor.setDelay(Duration), getDelayDuration() and deprecate setDelay(long), getDelay(). Thanks to Gary Gregory. +* DefaultFileMonitor implements AutoCloseable. Thanks to Gary Gregory. +* Add FalseFileFilter.INSTANCE and deprecate FalseFileFilter.FALSE. Thanks to Gary Gregory. +* Add TrueFileFilter.INSTANCE and deprecate TrueFileFilter.TRUE. Thanks to Gary Gregory. +* FileSystemOptions implements Comparable. Thanks to Gary Gregory. +* Add RandomAccessMode.from(AccessMode) and toAccessModes(). Thanks to Gary Gregory. +* Extract the layer separator character constant into LayeredFileName.LAYER_SEPARATOR. Thanks to Gary Gregory. +* Add github/codeql-action. +* VFS-821: Deprecate FileSelector#traverseDescendents in favor of traverseDescendants. Thanks to Marc Wrobel, Gary Gregory. +* VFS-821: Add active port range configuration for FTP client factory #318. Thanks to Maksym Perevertov, Gary Gregory. +* VFS-833: Make constructor FileSystemOptions(Map) public. Thanks to Kannan Ramamoorthy, Bernd Eckenfels, Gary Gregory. +* Add a BOM POM commons-vfs2-bom. Thanks to Gary Gregory. + +Fixed Bugs: +* VFS-854: Avoid debug-logging URL credentials. Thanks to Andrey Turbanov. +* VFS-853: Double wrapped weak FileListener can lose change notification with DelegateFileObject. Thanks to Bernd Eckenfels. +* Replace package.html with package-info.java #206. Thanks to Seth Falco. +* VFS-807: LocalFile.doGetOutputStream(boolean) for an existing file no longer truncates the file. Thanks to Gary Gregory, L. +* Update the Javadoc link to not lead to 404. #218. Thanks to wodencafe. +* VFS-810: Percent encoded backslashes in authority of URLs aren't allowed for WebDav. Thanks to Jan Aelbrecht, Gary Gregory. +* VFS-793: GenericFileName.getURI() returns invalid URI. Thanks to Vitali Nashkevich, Gary Gregory. +* Fix typos in error messages. Thanks to Gary Gregory. +* LocalFile: Fix exception message "Unknown message with code" and use an actual message code. Thanks to Gary Gregory. +* VFS-778: SFTP channel isn't returned to the pool when SftpFileObject.doGetOutputStream throws an exception. #215. Thanks to zhouwenqing, Gary Gregory. +* Fix OSGi "Unused Import-Package instructions". Thanks to Gary Gregory. +* VFS-813: NullPointerException needs a better message in SftpClientFactory when connect with private key. Thanks to Andrey Turbanov, Gary Gregory. +* VFS-811: Javadoc API links are broken in the commons-vfs project site #227. Thanks to Woonsan Ko, Gary Gregory. +* VFS-812: Don't throw FileSystemException when closing file content output stream using a BufferedOutputStream #228. Thanks to XenoAmess, Gary Gregory. +* VFS-814: FtpFileObject: re-fetch MDTM after refresh #238. Thanks to Luke Wood, Gary Gregory. +* Simplify conditions and avoid extra checks #253. Thanks to Arturo Bernal. +* Refactor AbstractFileObject#getOutputStream() #151. Thanks to Boris Petrov, Gary Gregory. +* VFS-770: FileSystemManager.createFileSystem(FileObject) fails on Gzip files. #92. Thanks to Thomas BELOT, PeterAlfredLee, Gary Gregory. +* Simplify/remove redundant operations. #258. Thanks to Arturo Bernal. +* SFTP: Memory leak because AbstractFileProvider#findFileSystem. Thanks to Tobias Gierke, Gary Gregory. +* Fix typos #275, #276, #277. Thanks to Marc Wrobel. +* Fix links in Javadoc and documentations #284. Thanks to Marc Wrobel. +* [SFTP] Handle the case where a user does not have any groups #280. Thanks to Mark van der Walle, Gary Gregory. +* The dependency hadoop-hdfs-client is not set as optional #291. Thanks to ymenager. +* AbstractFileObject uses the wrong exception for "cause" #316. Thanks to Boris Petrov. +* JUnit5 assertThrows SftpFileSystemGroupsTests #323. Thanks to John Patrick. +* VFS-825: Fix for GZip input and output stream results in StackOverflowError #322. Thanks to Anthony Goubard. +* MonitorInputStream.read(byte[], int, int) and read() should be synchronized like the superclass BufferedInputStream. Thanks to Gary Gregory. +* VFS-683: Class loader thread safety #367. Thanks to Daryl Odnert, Otto Fowler, Bernd Eckenfels, Dave MacDonald, Ivan Bella, Gary Gregory. +* VFS-832: Sftp channel not put back in doGetInputStream #370. Thanks to Wangerry, Gary Gregory. +* [StepSecurity] ci: Harden GitHub Actions #401. Thanks to step-security-bot, Gary Gregory. +* VFS-846: Resolve a FileName to correct FileType #424. Thanks to beise, Gary Gregory. +* VFS-844: Prevent that source files urlString is twice URIEncoded #423. Thanks to beise, Gary Gregory. +* VFS-843: Close the HttpConnection after consuming the entire HttpEntity #421. Thanks to beise, Gary Gregory. +* VFS-841: Copy the Main class for testing with Jackrabbit Standalone Components instead of reusing #409. Thanks to Woonsan Ko, Gary Gregory. +* VFS-849: HttpConnection resources not properly cleaned up in webdav request #428. Thanks to beise, Gary Gregory. +* Don't use deprecated methods in org.apache.commons.vfs2.provider.ftp.FtpClientFactory. Thanks to Gary Gregory. +* Reduce deprecated calls in org.apache.commons.vfs2.provider.http5. Thanks to Gary Gregory. +* DelegatingFileSystemOptionsBuilder.setConfigClass[es](FileSystemOptions, String, String, Class) now throw the more general ReflectiveOperationException instead of 2 subclasses. Thanks to Gary Gregory. +* VFS-524: A URI with an IPv6 address can't be parsed out correctly #438. Thanks to Alex, Fedor Yudanov, Gary Gregory. +* Port assertions to JUnit 5 APIs. Thanks to Gary Gregory. +* Scheme "http" now uses Apache HttpClient 5 instead of HttpClient 3. Thanks to Gary Gregory. +* Scheme "https" now uses Apache HttpClient 5 instead of HttpClient 3. Thanks to Gary Gregory. +* Deprecate package org.apache.commons.vfs2.provider.http in favor of org.apache.commons.vfs2.provider.http5. Thanks to Gary Gregory. +* Deprecate package org.apache.commons.vfs2.provider.https in favor of org.apache.commons.vfs2.provider.http5s. Thanks to Gary Gregory. +* Deprecate package org.apache.commons.vfs2.provider.http4 in favor of org.apache.commons.vfs2.provider.http5. Thanks to Gary Gregory. +* Deprecate package org.apache.commons.vfs2.provider.http4s in favor of org.apache.commons.vfs2.provider.http5s. Thanks to Gary Gregory. +* Support URLencoding during normalization #396. Thanks to Arnout Engelen, Gary Gregory. +* Add some documentation to make the unit tests easier to follow #556. Thanks to Arnout Engelen, Gary Gregory. +* Fix or address PMD warnings UnnecessaryReturn, UnusedLocalVariable, UnnecessaryFullyQualifiedName, UnnecessaryImport, and so on. Thanks to Gary Gregory. +* Simplify UriParser #558. Thanks to Arnout Engelen. + +Changes +------- + +* Bump actions/cache and others. Thanks to Dependabot, Gary Gregory. +* Bump actions/checkout #217, #220, #245, #315, and others. Thanks to Dependabot, Gary Gregory. +* Bump actions/setup-java #324, and others. Thanks to Gary Gregory, Dependabot. +* Bump actions/upload-artifact from #327, and others. Thanks to Dependabot. +* Bump jakarta.mail from 1.6.7 to 2.0.1 #200. Thanks to Dependabot. +* Bump commons.animal-sniffer.version from 1.19 to 1.21. Thanks to Gary Gregory. +* Bump com.puppycrawl.tools:checkstyle from 8.44 to 9.3 #211. Thanks to Gary Gregory. +* Bump com.github.spotbugs:spotbugs from 4.3.0 to 4.7.3 #216, #269, #319. Thanks to Dependabot, Gary Gregory. +* Bump spotbugs-maven-plugin from 4.3.0 to 4.7.3.0, #229, #236. #264, #282, #331, #333. Thanks to Gary Gregory, Dependabot. +* Bump org.apache.jackrabbit:jackrabbit-standalone-components from 2.21.7 to 2.20.16, 2.21.x is beta only. Thanks to Dependabot, Gary Gregory. +* Bump org.apache.httpcomponents.client5:httpclient5 from 5.1 to 5.4-beta1 #561. Thanks to Gary Gregory, Dependabot. +* Bump org.apache.httpcomponents.core5:httpcore5 from 5.1.5 to 5.3-beta1 #369, #399, #429, #447, #559. Thanks to Dependabot. +* Bump org.apache.mina:mina-core from 2.1.4 to 2.1.8. Thanks to Gary Gregory, Dependabot. +* Bump maven-pmd-plugin from 3.14.0 to 3.19.0 #223, #294, #304. Thanks to Dependabot, Gary Gregory. +* Bump net.sourceforge.pmd:pmd-* from 6.36.0 to 6.53.0 #208, #247, #256, #261, #266, #270, #283, #339, #361. Thanks to Dependabot, Gary Gregory. +* Bump org.mockito:mockito-core from 3.11.2 to 4.11.0 #263, #292, #308, #337, #355, #359. Thanks to Gary Gregory, Dependabot. +* Bump maven-javadoc-plugin from 3.3.0 to 3.4.1, #293. Thanks to Gary Gregory, Dependabot. +* Bump biz.aQute.bnd:biz.aQute.bndlib from 5.3.0 to 6.3.1. Thanks to Gary Gregory. +* Bump commons.japicmp.version from 0.15.3 to 0.16.0. Thanks to Gary Gregory. +* Replace JUnit 4.13.2 with 5.9.1 #281, #306. Thanks to Gary Gregory, John Patrick, Dependabot. +* Bump org.apache.httpcomponents:httpcore-nio from 4.4.14 to 4.4.16, #341. Thanks to Gary Gregory, Dependabot. +* Bump Apache Log4j 2.14.1 to 2.23.1 [Tests] #226, #230, #305, #378, #448, #461, #487, #499. Thanks to Gary Gregory, Dependabot. +* Bump ftpserver-core from 1.1.1 to 1.1.2 #235. Thanks to XenoAmess. +* Bump hadoop.version from 3.3.1 to 3.3.6 #246, #262, #290, #386, #402. Thanks to Dependabot. +* Bump slf4j.version from 1.7.26 to 2.0.15 #484, #486, #524, #575, #580. Thanks to Dependabot. +* Bump org.apache.commons:commons-parent from 52 to 72 #497. Thanks to Dependabot, Gary Gregory. +* Bump org.ow2.asm:asm from 9.2 to 9.4. Thanks to Gary Gregory. +* Bump commons.jacoco.version from 0.8.7 to 0.8.8. Thanks to Gary Gregory. +* Bump commons.surefire.version from 3.0.0-M5 to 3.0.0-M7. Thanks to Gary Gregory. +* Bump Apache Commons BCEL from 6.5.0 to 6.10.0 #346, #451, #522, #569. Thanks to Gary Gregory, Dependabot. +* Bump maven-checkstyle-plugin from 3.1.2 to 3.2.0 #321 Thanks to Dependabot. +* Bump commons-compress from 1.21 to 1.27.0 #329, #385, $498, #535, #579. Thanks to Dependabot, Gary Gregory. +* Bump commons-net:commons-net from 3.8.0 to 3.11.1 #546, #548. Thanks to Gary Gregory, Dependabot. +* Bump httpclient from 4.5.13 to 4.5.14 #344. Thanks to Dependabot. +* Bump commons-io:commons-io from 2.11.0 to 2.16.1 #515. Thanks to Gary Gregory. +* Bump commons-codec:commons-codec from 1.15 to 1.17.1 #480, #530, #567. Thanks to Gary Gregory. +* Bump org.apache.commons:commons-lang3 from 3.12.0 to 3.16.0 #568, #577. Thanks to Gary Gregory. +* Bump org.codehaus.mojo:exec-maven-plugin from 3.1.0 to 3.4.0 #445, #536, #576. Thanks to Dependabot. +* Bump commons-logging:commons-logging from 1.2 to 1.3.3, #531, #563. Thanks to Gary Gregory. +* Bump org.codehaus.mojo:exec-maven-plugin from 3.1.1 to 3.2.0 #494. Thanks to Gary Gregory. +* Bump org.apache.commons:commons-collections4 from 4.4 to 4.5.0-M2. Thanks to Gary Gregory. +* Bump ant:ant 1.6.5 to org.apache.ant:ant 1.10.14. Thanks to Gary Gregory. + + +Historical list of changes: https://commons.apache.org/proper/commons-vfs/changes-report.html + +For complete information on Apache Commons VFS Project, including instructions on how to submit bug reports, +patches, or suggestions for improvement, see the Apache Commons VFS Project website: + +https://commons.apache.org/proper/commons-vfs/ + +Download page: https://commons.apache.org/proper/commons-vfs/download_vfs.cgi + ----------------------------------------------------------------------------- Apache Commons VFS Project 2.9.0 diff --git a/commons-vfs2-ant/src/main/java/org/apache/commons/vfs2/tasks/ShowFileTask.java b/commons-vfs2-ant/src/main/java/org/apache/commons/vfs2/tasks/ShowFileTask.java index d0375f597e..3d74993988 100644 --- a/commons-vfs2-ant/src/main/java/org/apache/commons/vfs2/tasks/ShowFileTask.java +++ b/commons-vfs2-ant/src/main/java/org/apache/commons/vfs2/tasks/ShowFileTask.java @@ -1,148 +1,148 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.vfs2.tasks; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.nio.charset.Charset; -import java.util.Date; - -import org.apache.commons.vfs2.FileContent; -import org.apache.commons.vfs2.FileObject; -import org.apache.tools.ant.BuildException; - -/** - * An Ant task that writes the details of a file to Ant's log. - */ -public class ShowFileTask extends VfsTask { - - private static final String INDENT = " "; - private String url; - private boolean showContent; - private boolean recursive; - - /** - * Constructs a new instance. - */ - public ShowFileTask() { - // empty - } - - /** - * Executes the task. - * - * @throws BuildException if any exception is thrown. - */ - @Override - public void execute() throws BuildException { - try { - try (FileObject file = resolveFile(url)) { - log("Details of " + file.getPublicURIString()); - showFile(file, INDENT); - } - } catch (final Exception e) { - throw new BuildException(e); - } - } - - /** - * Writes the content of the file to Ant log. - */ - private void logContent(final FileObject file, final String prefix) throws IOException { - try (FileContent content = file.getContent(); - InputStream instr = content.getInputStream(); - BufferedReader reader = new BufferedReader(new InputStreamReader(instr, Charset.defaultCharset()))) { - while (true) { - final String line = reader.readLine(); - if (line == null) { - break; - } - log(prefix + line); - } - } - } - - /** - * The URL of the file to display. - * - * @param url The url of the file. - */ - public void setFile(final String url) { - this.url = url; - } - - /** - * Recursively shows the descendants of the file. - * - * @param recursive true if descendants should be shown. - */ - public void setRecursive(final boolean recursive) { - this.recursive = recursive; - } - - /** - * Shows the content. Assumes the content is text, encoded using the platform's default encoding. - * - * @param showContent true if the content should be shown. - */ - public void setShowContent(final boolean showContent) { - this.showContent = showContent; - } - - /** - * Logs the details of a file. - */ - private void showFile(final FileObject file, final String prefix) throws IOException { - // Write details - final StringBuilder msg = new StringBuilder(prefix); - msg.append(file.getName().getBaseName()); - if (file.exists()) { - msg.append(" ("); - msg.append(file.getType().getName()); - msg.append(")"); - } else { - msg.append(" (unknown)"); - } - log(msg.toString()); - - if (file.exists()) { - final String newPrefix = prefix + INDENT; - if (file.getType().hasContent()) { - try (FileContent content = file.getContent()) { - log(newPrefix + "Content-Length: " + content.getSize()); - log(newPrefix + "Last-Modified" + new Date(content.getLastModifiedTime())); - } - if (showContent) { - log(newPrefix + "Content:"); - logContent(file, newPrefix); - } - } - if (file.getType().hasChildren()) { - final FileObject[] children = file.getChildren(); - for (final FileObject child : children) { - if (recursive) { - showFile(child, newPrefix); - } else { - log(newPrefix + child.getName().getBaseName()); - } - } - } - } - } -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.vfs2.tasks; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.Charset; +import java.util.Date; + +import org.apache.commons.vfs2.FileContent; +import org.apache.commons.vfs2.FileObject; +import org.apache.tools.ant.BuildException; + +/** + * An Ant task that writes the details of a file to Ant's log. + */ +public class ShowFileTask extends VfsTask { + + private static final String INDENT = " "; + private String url; + private boolean showContent; + private boolean recursive; + + /** + * Constructs a new instance. + */ + public ShowFileTask() { + // empty + } + + /** + * Executes the task. + * + * @throws BuildException if any exception is thrown. + */ + @Override + public void execute() throws BuildException { + try { + try (FileObject file = resolveFile(url)) { + log("Details of " + file.getPublicURIString()); + showFile(file, INDENT); + } + } catch (final Exception e) { + throw new BuildException(e); + } + } + + /** + * Writes the content of the file to Ant log. + */ + private void logContent(final FileObject file, final String prefix) throws IOException { + try (FileContent content = file.getContent(); + InputStream instr = content.getInputStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(instr, Charset.defaultCharset()))) { + while (true) { + final String line = reader.readLine(); + if (line == null) { + break; + } + log(prefix + line); + } + } + } + + /** + * The URL of the file to display. + * + * @param url The url of the file. + */ + public void setFile(final String url) { + this.url = url; + } + + /** + * Recursively shows the descendants of the file. + * + * @param recursive true if descendants should be shown. + */ + public void setRecursive(final boolean recursive) { + this.recursive = recursive; + } + + /** + * Shows the content. Assumes the content is text, encoded using the platform's default encoding. + * + * @param showContent true if the content should be shown. + */ + public void setShowContent(final boolean showContent) { + this.showContent = showContent; + } + + /** + * Logs the details of a file. + */ + private void showFile(final FileObject file, final String prefix) throws IOException { + // Write details + final StringBuilder msg = new StringBuilder(prefix); + msg.append(file.getName().getBaseName()); + if (file.exists()) { + msg.append(" ("); + msg.append(file.getType().getName()); + msg.append(")"); + } else { + msg.append(" (unknown)"); + } + log(msg.toString()); + + if (file.exists()) { + final String newPrefix = prefix + INDENT; + if (file.getType().hasContent()) { + try (FileContent content = file.getContent()) { + log(newPrefix + "Content-Length: " + content.getSize()); + log(newPrefix + "Last-Modified" + new Date(content.getLastModifiedTime())); + } + if (showContent) { + log(newPrefix + "Content:"); + logContent(file, newPrefix); + } + } + if (file.getType().hasChildren()) { + final FileObject[] children = file.getChildren(); + for (final FileObject child : children) { + if (recursive) { + showFile(child, newPrefix); + } else { + log(newPrefix + child.getName().getBaseName()); + } + } + } + } + } +} diff --git a/commons-vfs2-examples/src/site/xdoc/index.xml b/commons-vfs2-examples/src/site/xdoc/index.xml index b3d2abe023..19cc236f73 100644 --- a/commons-vfs2-examples/src/site/xdoc/index.xml +++ b/commons-vfs2-examples/src/site/xdoc/index.xml @@ -1,104 +1,104 @@ - - - - - - Apache Commons VFS Examples - Apache Commons Developers - - - - -
-

- This example module contains sample - source code for learning how to use Apache - Commons VFS in the org.apache.commons.vfs2.example package. -

-

- The org.apache.commons.vfs2.libcheck package contains some Java - classes to exercise some of the functionality of the libraries (dependencies) - used by Apache Commons VFS. This is mainly for the maintainers of VFS providers. -

-
- -
- -

- The Commons VFS Shell is an example for a command line shell. - It can be used to play with different providers and to verify - an installation. -

- -

- Check out the page VfsExampleShell - on the Apache Commons Wiki for a number of examples. In particular you can use the info - command to list the schemes which are auto discovered by the StandardFileSystemManager. -

- -

- The following examples assume an environment variable REP which points to a populated local Maven - repository. As an alternative you can download the required - dependencies manually. (The commons-collection4 - dependency is not needed for the VFS Shell as it does not use LRUFilesCache.) Because - of licensing restrictions the sandbox component must be - built locally and then installed into the repository. -

- - - - - - - - -
- - -
- + + + + + + Apache Commons VFS Examples + Apache Commons Developers + + + + +
+

+ This example module contains sample + source code for learning how to use Apache + Commons VFS in the org.apache.commons.vfs2.example package. +

+

+ The org.apache.commons.vfs2.libcheck package contains some Java + classes to exercise some of the functionality of the libraries (dependencies) + used by Apache Commons VFS. This is mainly for the maintainers of VFS providers. +

+
+ +
+ +

+ The Commons VFS Shell is an example for a command line shell. + It can be used to play with different providers and to verify + an installation. +

+ +

+ Check out the page VfsExampleShell + on the Apache Commons Wiki for a number of examples. In particular you can use the info + command to list the schemes which are auto discovered by the StandardFileSystemManager. +

+ +

+ The following examples assume an environment variable REP which points to a populated local Maven + repository. As an alternative you can download the required + dependencies manually. (The commons-collection4 + dependency is not needed for the VFS Shell as it does not use LRUFilesCache.) Because + of licensing restrictions the sandbox component must be + built locally and then installed into the repository. +

+ + + + + + + + +
+ + +
+ diff --git a/commons-vfs2-hdfs/src/main/java/org/apache/commons/vfs2/provider/hdfs/HdfsFileObject.java b/commons-vfs2-hdfs/src/main/java/org/apache/commons/vfs2/provider/hdfs/HdfsFileObject.java index b8f009a6a9..d169b77e75 100644 --- a/commons-vfs2-hdfs/src/main/java/org/apache/commons/vfs2/provider/hdfs/HdfsFileObject.java +++ b/commons-vfs2-hdfs/src/main/java/org/apache/commons/vfs2/provider/hdfs/HdfsFileObject.java @@ -1,313 +1,313 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.vfs2.provider.hdfs; - -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.stream.Stream; - -import org.apache.commons.vfs2.FileNotFolderException; -import org.apache.commons.vfs2.FileObject; -import org.apache.commons.vfs2.FileSystemException; -import org.apache.commons.vfs2.FileType; -import org.apache.commons.vfs2.RandomAccessContent; -import org.apache.commons.vfs2.provider.AbstractFileName; -import org.apache.commons.vfs2.provider.AbstractFileObject; -import org.apache.commons.vfs2.util.RandomAccessMode; -import org.apache.hadoop.fs.FileStatus; -import org.apache.hadoop.fs.FileSystem; -import org.apache.hadoop.fs.Path; - -/** - * A VFS representation of an HDFS file. - * - * @since 2.1 - */ -public class HdfsFileObject extends AbstractFileObject { - - private final HdfsFileSystem fs; - private final FileSystem hdfs; - private final Path path; - private FileStatus stat; - - /** - * Constructs a new HDFS FileObject - * - * @param name FileName - * @param fs HdfsFileSystem instance - * @param hdfs Hadoop FileSystem instance - * @param path Path to the file in HDFS - */ - protected HdfsFileObject(final AbstractFileName name, final HdfsFileSystem fs, final FileSystem hdfs, - final Path path) { - super(name, fs); - this.fs = fs; - this.hdfs = hdfs; - this.path = path; - } - - /** - * @see org.apache.commons.vfs2.provider.AbstractFileObject#canRenameTo(org.apache.commons.vfs2.FileObject) - */ - @Override - public boolean canRenameTo(final FileObject newfile) { - if (!super.canRenameTo(newfile)) { - return false; - } - try { - return hdfs.getFileStatus(new Path(newfile.getName().getPath())) == null; - } catch (final FileNotFoundException e) { - return false; - } catch (final IOException e) { - throw new IllegalStateException(e); - } - } - - /** - * @see org.apache.commons.vfs2.provider.AbstractFileObject#doAttach() - */ - @Override - protected void doAttach() throws Exception { - try { - stat = hdfs.getFileStatus(path); - } catch (final FileNotFoundException e) { - stat = null; - } - } - - /** - * @see org.apache.commons.vfs2.provider.AbstractFileObject#doCreateFolder() - * @since 2.7.0 - */ - @Override - protected void doCreateFolder() throws Exception { - hdfs.mkdirs(path); - } - - /** - * @see org.apache.commons.vfs2.provider.AbstractFileObject#doDelete() - * @since 2.7.0 - */ - @Override - protected void doDelete() throws Exception { - hdfs.delete(path, true); - } - - /** - * @see org.apache.commons.vfs2.provider.AbstractFileObject#doGetAttributes() - */ - @Override - protected Map doGetAttributes() throws Exception { - if (null == stat) { - return super.doGetAttributes(); - } - final Map attrs = new HashMap<>(); - attrs.put(HdfsFileAttributes.LAST_ACCESS_TIME.toString(), stat.getAccessTime()); - attrs.put(HdfsFileAttributes.BLOCK_SIZE.toString(), stat.getBlockSize()); - attrs.put(HdfsFileAttributes.GROUP.toString(), stat.getGroup()); - attrs.put(HdfsFileAttributes.OWNER.toString(), stat.getOwner()); - attrs.put(HdfsFileAttributes.PERMISSIONS.toString(), stat.getPermission().toString()); - attrs.put(HdfsFileAttributes.LENGTH.toString(), stat.getLen()); - attrs.put(HdfsFileAttributes.MODIFICATION_TIME.toString(), stat.getModificationTime()); - return attrs; - } - - /** - * @see org.apache.commons.vfs2.provider.AbstractFileObject#doGetContentSize() - */ - @Override - protected long doGetContentSize() throws Exception { - return stat.getLen(); - } - - /** - * @see org.apache.commons.vfs2.provider.AbstractFileObject#doGetInputStream(int) - */ - @Override - protected InputStream doGetInputStream(final int bufferSize) throws Exception { - return hdfs.open(path, bufferSize); - } - - /** - * @see org.apache.commons.vfs2.provider.AbstractFileObject#doGetLastModifiedTime() - */ - @Override - protected long doGetLastModifiedTime() throws Exception { - doAttach(); - if (null != stat) { - return stat.getModificationTime(); - } - return -1; - } - - /** - * @see org.apache.commons.vfs2.provider.AbstractFileObject#doGetOutputStream(boolean) - * @since 2.7.0 - */ - @Override - protected OutputStream doGetOutputStream(final boolean append) throws Exception { - if (append) { - throw new FileSystemException("vfs.provider/write-append-not-supported.error", path.getName()); - } - return hdfs.create(path); - } - - /** - * @see org.apache.commons.vfs2.provider.AbstractFileObject#doGetRandomAccessContent - * (org.apache.commons.vfs2.util.RandomAccessMode) - */ - @Override - protected RandomAccessContent doGetRandomAccessContent(final RandomAccessMode mode) throws Exception { - if (mode.equals(RandomAccessMode.READWRITE)) { - throw new UnsupportedOperationException(); - } - return new HdfsRandomAccessContent(path, hdfs); - } - - /** - * @see org.apache.commons.vfs2.provider.AbstractFileObject#doGetType() - */ - @Override - protected FileType doGetType() throws Exception { - try { - doAttach(); - if (null == stat) { - return FileType.IMAGINARY; - } - if (stat.isDirectory()) { - return FileType.FOLDER; - } - return FileType.FILE; - } catch (final FileNotFoundException fnfe) { - return FileType.IMAGINARY; - } - } - - /** - * @see org.apache.commons.vfs2.provider.AbstractFileObject#doIsHidden() - */ - @Override - protected boolean doIsHidden() throws Exception { - return false; - } - - /** - * @see org.apache.commons.vfs2.provider.AbstractFileObject#doIsReadable() - */ - @Override - protected boolean doIsReadable() throws Exception { - return true; - } - - /** - * @see org.apache.commons.vfs2.provider.AbstractFileObject#doIsWriteable() - */ - @Override - protected boolean doIsWriteable() throws Exception { - return true; - } - - /** - * @see org.apache.commons.vfs2.provider.AbstractFileObject#doListChildren() - */ - @Override - protected String[] doListChildren() throws Exception { - if (doGetType() != FileType.FOLDER) { - throw new FileNotFolderException(this); - } - - final FileStatus[] fileStatuses = hdfs.listStatus(path); - return Stream.of(fileStatuses).filter(Objects::nonNull).map(status -> status.getPath().getName()).toArray(String[]::new); - } - - /** - * @see org.apache.commons.vfs2.provider.AbstractFileObject#doListChildrenResolved() - */ - @Override - protected FileObject[] doListChildrenResolved() throws Exception { - if (doGetType() != FileType.FOLDER) { - return null; - } - final String[] children = doListChildren(); - final FileObject[] fo = new FileObject[children.length]; - for (int i = 0; i < children.length; i++) { - final Path p = new Path(path, children[i]); - fo[i] = fs.resolveFile(p.toUri().toString()); - } - return fo; - } - - /** - * @see org.apache.commons.vfs2.provider.AbstractFileObject#doRemoveAttribute(String) - */ - @Override - protected void doRemoveAttribute(final String attrName) throws Exception { - throw new UnsupportedOperationException(); - } - - /** - * @see org.apache.commons.vfs2.provider.AbstractFileObject#doRename(FileObject) - * @since 2.7.0 - */ - @Override - protected void doRename(final FileObject newfile) throws Exception { - hdfs.rename(path, new Path(newfile.getName().getPath())); - } - - /** - * @see org.apache.commons.vfs2.provider.AbstractFileObject#doSetAttribute(String, Object) - */ - @Override - protected void doSetAttribute(final String attrName, final Object value) throws Exception { - throw new UnsupportedOperationException(); - } - - /** - * @see org.apache.commons.vfs2.provider.AbstractFileObject#doSetLastModifiedTime(long) - */ - @Override - protected boolean doSetLastModifiedTime(final long modtime) throws Exception { - try { - hdfs.setTimes(path, modtime, System.currentTimeMillis()); - } catch (final IOException ioe) { - throw new FileSystemException(ioe); - } - return true; - } - - /** - * @see org.apache.commons.vfs2.provider.AbstractFileObject#exists() - * @return boolean true if file exists, false if not - */ - @Override - public boolean exists() throws FileSystemException { - try { - doAttach(); - return stat != null; - } catch (final FileNotFoundException fne) { - return false; - } catch (final Exception e) { - throw new FileSystemException("Unable to check existence ", e); - } - } - -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.vfs2.provider.hdfs; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Stream; + +import org.apache.commons.vfs2.FileNotFolderException; +import org.apache.commons.vfs2.FileObject; +import org.apache.commons.vfs2.FileSystemException; +import org.apache.commons.vfs2.FileType; +import org.apache.commons.vfs2.RandomAccessContent; +import org.apache.commons.vfs2.provider.AbstractFileName; +import org.apache.commons.vfs2.provider.AbstractFileObject; +import org.apache.commons.vfs2.util.RandomAccessMode; +import org.apache.hadoop.fs.FileStatus; +import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.fs.Path; + +/** + * A VFS representation of an HDFS file. + * + * @since 2.1 + */ +public class HdfsFileObject extends AbstractFileObject { + + private final HdfsFileSystem fs; + private final FileSystem hdfs; + private final Path path; + private FileStatus stat; + + /** + * Constructs a new HDFS FileObject + * + * @param name FileName + * @param fs HdfsFileSystem instance + * @param hdfs Hadoop FileSystem instance + * @param path Path to the file in HDFS + */ + protected HdfsFileObject(final AbstractFileName name, final HdfsFileSystem fs, final FileSystem hdfs, + final Path path) { + super(name, fs); + this.fs = fs; + this.hdfs = hdfs; + this.path = path; + } + + /** + * @see org.apache.commons.vfs2.provider.AbstractFileObject#canRenameTo(org.apache.commons.vfs2.FileObject) + */ + @Override + public boolean canRenameTo(final FileObject newfile) { + if (!super.canRenameTo(newfile)) { + return false; + } + try { + return hdfs.getFileStatus(new Path(newfile.getName().getPath())) == null; + } catch (final FileNotFoundException e) { + return false; + } catch (final IOException e) { + throw new IllegalStateException(e); + } + } + + /** + * @see org.apache.commons.vfs2.provider.AbstractFileObject#doAttach() + */ + @Override + protected void doAttach() throws Exception { + try { + stat = hdfs.getFileStatus(path); + } catch (final FileNotFoundException e) { + stat = null; + } + } + + /** + * @see org.apache.commons.vfs2.provider.AbstractFileObject#doCreateFolder() + * @since 2.7.0 + */ + @Override + protected void doCreateFolder() throws Exception { + hdfs.mkdirs(path); + } + + /** + * @see org.apache.commons.vfs2.provider.AbstractFileObject#doDelete() + * @since 2.7.0 + */ + @Override + protected void doDelete() throws Exception { + hdfs.delete(path, true); + } + + /** + * @see org.apache.commons.vfs2.provider.AbstractFileObject#doGetAttributes() + */ + @Override + protected Map doGetAttributes() throws Exception { + if (null == stat) { + return super.doGetAttributes(); + } + final Map attrs = new HashMap<>(); + attrs.put(HdfsFileAttributes.LAST_ACCESS_TIME.toString(), stat.getAccessTime()); + attrs.put(HdfsFileAttributes.BLOCK_SIZE.toString(), stat.getBlockSize()); + attrs.put(HdfsFileAttributes.GROUP.toString(), stat.getGroup()); + attrs.put(HdfsFileAttributes.OWNER.toString(), stat.getOwner()); + attrs.put(HdfsFileAttributes.PERMISSIONS.toString(), stat.getPermission().toString()); + attrs.put(HdfsFileAttributes.LENGTH.toString(), stat.getLen()); + attrs.put(HdfsFileAttributes.MODIFICATION_TIME.toString(), stat.getModificationTime()); + return attrs; + } + + /** + * @see org.apache.commons.vfs2.provider.AbstractFileObject#doGetContentSize() + */ + @Override + protected long doGetContentSize() throws Exception { + return stat.getLen(); + } + + /** + * @see org.apache.commons.vfs2.provider.AbstractFileObject#doGetInputStream(int) + */ + @Override + protected InputStream doGetInputStream(final int bufferSize) throws Exception { + return hdfs.open(path, bufferSize); + } + + /** + * @see org.apache.commons.vfs2.provider.AbstractFileObject#doGetLastModifiedTime() + */ + @Override + protected long doGetLastModifiedTime() throws Exception { + doAttach(); + if (null != stat) { + return stat.getModificationTime(); + } + return -1; + } + + /** + * @see org.apache.commons.vfs2.provider.AbstractFileObject#doGetOutputStream(boolean) + * @since 2.7.0 + */ + @Override + protected OutputStream doGetOutputStream(final boolean append) throws Exception { + if (append) { + throw new FileSystemException("vfs.provider/write-append-not-supported.error", path.getName()); + } + return hdfs.create(path); + } + + /** + * @see org.apache.commons.vfs2.provider.AbstractFileObject#doGetRandomAccessContent + * (org.apache.commons.vfs2.util.RandomAccessMode) + */ + @Override + protected RandomAccessContent doGetRandomAccessContent(final RandomAccessMode mode) throws Exception { + if (mode.equals(RandomAccessMode.READWRITE)) { + throw new UnsupportedOperationException(); + } + return new HdfsRandomAccessContent(path, hdfs); + } + + /** + * @see org.apache.commons.vfs2.provider.AbstractFileObject#doGetType() + */ + @Override + protected FileType doGetType() throws Exception { + try { + doAttach(); + if (null == stat) { + return FileType.IMAGINARY; + } + if (stat.isDirectory()) { + return FileType.FOLDER; + } + return FileType.FILE; + } catch (final FileNotFoundException fnfe) { + return FileType.IMAGINARY; + } + } + + /** + * @see org.apache.commons.vfs2.provider.AbstractFileObject#doIsHidden() + */ + @Override + protected boolean doIsHidden() throws Exception { + return false; + } + + /** + * @see org.apache.commons.vfs2.provider.AbstractFileObject#doIsReadable() + */ + @Override + protected boolean doIsReadable() throws Exception { + return true; + } + + /** + * @see org.apache.commons.vfs2.provider.AbstractFileObject#doIsWriteable() + */ + @Override + protected boolean doIsWriteable() throws Exception { + return true; + } + + /** + * @see org.apache.commons.vfs2.provider.AbstractFileObject#doListChildren() + */ + @Override + protected String[] doListChildren() throws Exception { + if (doGetType() != FileType.FOLDER) { + throw new FileNotFolderException(this); + } + + final FileStatus[] fileStatuses = hdfs.listStatus(path); + return Stream.of(fileStatuses).filter(Objects::nonNull).map(status -> status.getPath().getName()).toArray(String[]::new); + } + + /** + * @see org.apache.commons.vfs2.provider.AbstractFileObject#doListChildrenResolved() + */ + @Override + protected FileObject[] doListChildrenResolved() throws Exception { + if (doGetType() != FileType.FOLDER) { + return null; + } + final String[] children = doListChildren(); + final FileObject[] fo = new FileObject[children.length]; + for (int i = 0; i < children.length; i++) { + final Path p = new Path(path, children[i]); + fo[i] = fs.resolveFile(p.toUri().toString()); + } + return fo; + } + + /** + * @see org.apache.commons.vfs2.provider.AbstractFileObject#doRemoveAttribute(String) + */ + @Override + protected void doRemoveAttribute(final String attrName) throws Exception { + throw new UnsupportedOperationException(); + } + + /** + * @see org.apache.commons.vfs2.provider.AbstractFileObject#doRename(FileObject) + * @since 2.7.0 + */ + @Override + protected void doRename(final FileObject newfile) throws Exception { + hdfs.rename(path, new Path(newfile.getName().getPath())); + } + + /** + * @see org.apache.commons.vfs2.provider.AbstractFileObject#doSetAttribute(String, Object) + */ + @Override + protected void doSetAttribute(final String attrName, final Object value) throws Exception { + throw new UnsupportedOperationException(); + } + + /** + * @see org.apache.commons.vfs2.provider.AbstractFileObject#doSetLastModifiedTime(long) + */ + @Override + protected boolean doSetLastModifiedTime(final long modtime) throws Exception { + try { + hdfs.setTimes(path, modtime, System.currentTimeMillis()); + } catch (final IOException ioe) { + throw new FileSystemException(ioe); + } + return true; + } + + /** + * @see org.apache.commons.vfs2.provider.AbstractFileObject#exists() + * @return boolean true if file exists, false if not + */ + @Override + public boolean exists() throws FileSystemException { + try { + doAttach(); + return stat != null; + } catch (final FileNotFoundException fne) { + return false; + } catch (final Exception e) { + throw new FileSystemException("Unable to check existence ", e); + } + } + +} diff --git a/commons-vfs2-jackrabbit2/src/main/java/org/apache/commons/vfs2/provider/webdav4/Webdav4FileObject.java b/commons-vfs2-jackrabbit2/src/main/java/org/apache/commons/vfs2/provider/webdav4/Webdav4FileObject.java index 89f0fe6157..52defe6335 100644 --- a/commons-vfs2-jackrabbit2/src/main/java/org/apache/commons/vfs2/provider/webdav4/Webdav4FileObject.java +++ b/commons-vfs2-jackrabbit2/src/main/java/org/apache/commons/vfs2/provider/webdav4/Webdav4FileObject.java @@ -1,664 +1,664 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.vfs2.provider.webdav4; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.net.HttpURLConnection; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.commons.vfs2.FileContentInfoFactory; -import org.apache.commons.vfs2.FileNotFolderException; -import org.apache.commons.vfs2.FileNotFoundException; -import org.apache.commons.vfs2.FileObject; -import org.apache.commons.vfs2.FileSystemException; -import org.apache.commons.vfs2.FileType; -import org.apache.commons.vfs2.NameScope; -import org.apache.commons.vfs2.provider.AbstractFileName; -import org.apache.commons.vfs2.provider.DefaultFileContent; -import org.apache.commons.vfs2.provider.GenericURLFileName; -import org.apache.commons.vfs2.provider.http4.Http4FileObject; -import org.apache.commons.vfs2.util.FileObjectUtils; -import org.apache.commons.vfs2.util.MonitorOutputStream; -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.apache.http.HttpStatus; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpPut; -import org.apache.http.client.methods.HttpUriRequest; -import org.apache.http.client.utils.DateUtils; -import org.apache.http.entity.ByteArrayEntity; -import org.apache.http.entity.ContentType; -import org.apache.http.util.EntityUtils; -import org.apache.jackrabbit.webdav.DavConstants; -import org.apache.jackrabbit.webdav.DavException; -import org.apache.jackrabbit.webdav.MultiStatus; -import org.apache.jackrabbit.webdav.MultiStatusResponse; -import org.apache.jackrabbit.webdav.client.methods.BaseDavRequest; -import org.apache.jackrabbit.webdav.client.methods.HttpCheckin; -import org.apache.jackrabbit.webdav.client.methods.HttpCheckout; -import org.apache.jackrabbit.webdav.client.methods.HttpDelete; -import org.apache.jackrabbit.webdav.client.methods.HttpMkcol; -import org.apache.jackrabbit.webdav.client.methods.HttpMove; -import org.apache.jackrabbit.webdav.client.methods.HttpPropfind; -import org.apache.jackrabbit.webdav.client.methods.HttpProppatch; -import org.apache.jackrabbit.webdav.client.methods.HttpVersionControl; -import org.apache.jackrabbit.webdav.property.DavProperty; -import org.apache.jackrabbit.webdav.property.DavPropertyName; -import org.apache.jackrabbit.webdav.property.DavPropertyNameSet; -import org.apache.jackrabbit.webdav.property.DavPropertySet; -import org.apache.jackrabbit.webdav.property.DefaultDavProperty; -import org.apache.jackrabbit.webdav.version.DeltaVConstants; -import org.apache.jackrabbit.webdav.version.VersionControlledResource; -import org.apache.jackrabbit.webdav.xml.Namespace; -import org.w3c.dom.Node; - -/** - * A WebDAV file. - * - * @since 2.5.0 - */ -public class Webdav4FileObject extends Http4FileObject { - - /** - * An OutputStream that writes to a WebDAV resource. - *

- * TODO - Use piped stream to avoid temporary file. - *

- */ - private class WebdavOutputStream extends MonitorOutputStream { - private final Webdav4FileObject file; - - WebdavOutputStream(final Webdav4FileObject file) { - super(new ByteArrayOutputStream()); - this.file = file; - } - - private boolean createVersion(final String urlStr) { - try { - final HttpVersionControl request = setupRequest(new HttpVersionControl(urlStr)); - // AutoClose the underlying HTTP connection which is held by the response object - try (CloseableHttpResponse unused = (CloseableHttpResponse) executeRequest(request)) { - return true; - } - } catch (final Exception ex) { - return false; - } - } - - /** - * Called after this stream is closed. - */ - @Override - protected void onClose() throws IOException { - final HttpEntity entity = new ByteArrayEntity(((ByteArrayOutputStream) out).toByteArray()); - final GenericURLFileName fileName = (GenericURLFileName) getName(); - final String urlStr = toUrlString(fileName); - if (builder.isVersioning(getFileSystem().getFileSystemOptions())) { - DavPropertySet set = null; - boolean fileExists = true; - boolean isCheckedIn = true; - try { - set = getPropertyNames(fileName); - } catch (final FileNotFoundException fnfe) { - fileExists = false; - } - if (fileExists && set != null) { - if (set.contains(VersionControlledResource.CHECKED_OUT)) { - isCheckedIn = false; - } else if (!set.contains(VersionControlledResource.CHECKED_IN)) { - DavProperty prop = set.get(VersionControlledResource.AUTO_VERSION); - if (prop != null) { - prop = getProperty(fileName, VersionControlledResource.AUTO_VERSION); - if (DeltaVConstants.XML_CHECKOUT_CHECKIN.equals(prop.getValue())) { - createVersion(urlStr); - } - } - } - } - if (fileExists && isCheckedIn) { - try { - final HttpCheckout request = setupRequest(new HttpCheckout(urlStr)); - // AutoClose the underlying HTTP connection which is held by the response object - try (CloseableHttpResponse unused = (CloseableHttpResponse) executeRequest(request)) { - isCheckedIn = false; - } - } catch (final FileSystemException ex) { - log(ex); - } - } - - try { - final HttpPut request = new HttpPut(urlStr); - request.setEntity(entity); - setupRequest(request); - // AutoClose the underlying HTTP connection which is held by the response object - try (CloseableHttpResponse unused = (CloseableHttpResponse) executeRequest(request)) { - setUserName(fileName, urlStr); - } - } catch (final FileSystemException ex) { - if (!isCheckedIn) { - try { - final HttpCheckin request = new HttpCheckin(urlStr); - setupRequest(request); - // AutoClose the underlying HTTP connection which is held by the response object - try (CloseableHttpResponse unused = (CloseableHttpResponse) executeRequest(request)) { - isCheckedIn = true; - } - } catch (final Exception e) { - // Going to throw original. - log(e); - } - throw ex; - } - } - if (!fileExists) { - createVersion(urlStr); - try { - final DavPropertySet props = getPropertyNames(fileName); - isCheckedIn = !props.contains(VersionControlledResource.CHECKED_OUT); - } catch (final FileNotFoundException fnfe) { - log(fnfe); - } - } - if (!isCheckedIn) { - final HttpCheckin request = new HttpCheckin(urlStr); - setupRequest(request); - // AutoClose the underlying HTTP connection which is held by the response object - try (CloseableHttpResponse unused = (CloseableHttpResponse) executeRequest(request)) { - isCheckedIn = true; - } - } - } else { - final HttpPut request = new HttpPut(urlStr); - request.setEntity(entity); - setupRequest(request); - // AutoClose the underlying HTTP connection which is held by the response object - try (CloseableHttpResponse unused = (CloseableHttpResponse) executeRequest(request)) { - try { - setUserName(fileName, urlStr); - } catch (final IOException e) { - // Unable to set the user name. - log(e); - } - } - } - ((DefaultFileContent) file.getContent()).resetAttributes(); - } - - private void setUserName(final GenericURLFileName fileName, final String urlStr) throws IOException { - final DavPropertySet setProperties = new DavPropertySet(); - final DavPropertyNameSet removeProperties = new DavPropertyNameSet(); - String name = builder.getCreatorName(getFileSystem().getFileSystemOptions()); - final String userName = fileName.getUserName(); - if (name == null) { - name = userName; - } else if (userName != null) { - final String comment = "Modified by user " + userName; - setProperties.add(new DefaultDavProperty<>(DeltaVConstants.COMMENT, comment)); - } - setProperties.add(new DefaultDavProperty<>(DeltaVConstants.CREATOR_DISPLAYNAME, name)); - final HttpProppatch request = setupRequest(new HttpProppatch(urlStr, setProperties, removeProperties)); - // AutoClose the underlying HTTP connection which is held by the response object - try (CloseableHttpResponse res = (CloseableHttpResponse) executeRequest(request)) { - // TODO: workaround due to PMD violation 'Empty try body - you could rename the resource to 'ignored' - request.succeeded(res); - } - } - } - - /** The character set property name. */ - public static final DavPropertyName RESPONSE_CHARSET = DavPropertyName.create("response-charset"); - - /** - * An empty immutable {@code Webdav4FileObject} array. - */ - private static final Webdav4FileObject[] EMPTY_ARRAY = {}; - - /** The FileSystemConfigBuilder */ - private final Webdav4FileSystemConfigBuilder builder; - - /** - * Constructs a new instance. - * - * @param name file name. - * @param fileSystem file system. - * @throws FileSystemException if any error occurs - */ - protected Webdav4FileObject(final AbstractFileName name, final Webdav4FileSystem fileSystem) - throws FileSystemException { - this(name, fileSystem, Webdav4FileSystemConfigBuilder.getInstance()); - } - - /** - * Constructs a new instance. - * - * @param name file name. - * @param fileSystem file system. - * @param builder builds the file system configuration. - * @throws FileSystemException if any error occurs - */ - protected Webdav4FileObject(final AbstractFileName name, final Webdav4FileSystem fileSystem, - final Webdav4FileSystemConfigBuilder builder) throws FileSystemException { - super(name, fileSystem, builder); - this.builder = builder; - } - - /** - * Creates this file as a folder. - */ - @Override - protected void doCreateFolder() throws Exception { - final HttpMkcol request = setupRequest(new HttpMkcol(toUrlString((GenericURLFileName) getName()))); - try { - // AutoClose the underlying HTTP connection which is held by the response object - try (CloseableHttpResponse res = (CloseableHttpResponse) executeRequest(request)) { - // TODO: workaround due to PMD violation 'Empty try body - you could rename the resource to 'ignored' - request.succeeded(res); - } - } catch (final FileSystemException fse) { - throw new FileSystemException("vfs.provider.webdav/create-collection.error", getName(), fse); - } - } - - /** - * Deletes the file. - */ - @Override - protected void doDelete() throws Exception { - final HttpDelete request = setupRequest(new HttpDelete(toUrlString((GenericURLFileName) getName()))); - // AutoClose the underlying HTTP connection which is held by the response object - try (CloseableHttpResponse res = (CloseableHttpResponse) executeRequest(request)) { - // TODO: workaround due to PMD violation 'Empty try body - you could rename the resource to 'ignored' - request.succeeded(res); - } - } - - /** - * Returns the properties of the Webdav resource. - */ - @Override - protected Map doGetAttributes() throws Exception { - final Map attributes = new HashMap<>(); - try { - final GenericURLFileName fileName = (GenericURLFileName) getName(); - DavPropertySet properties = getProperties(fileName, DavConstants.PROPFIND_ALL_PROP, - new DavPropertyNameSet(), false); - for (final DavProperty property : properties) { - attributes.put(property.getName().toString(), property.getValue()); - } - properties = getPropertyNames(fileName); - for (DavProperty property : properties) { - if (!attributes.containsKey(property.getName().getName())) { - property = getProperty(fileName, property.getName()); - if (property != null) { - final Object name = property.getName(); - final Object value = property.getValue(); - if (name != null && value != null) { - attributes.put(name.toString(), value); - } - } - } - } - return attributes; - } catch (final Exception e) { - throw new FileSystemException("vfs.provider.webdav/get-attributes.error", getName(), e); - } - } - - /** - * Returns the size of the file content (in bytes). - */ - @Override - protected long doGetContentSize() throws Exception { - final DavProperty property = getProperty((GenericURLFileName) getName(), DavConstants.PROPERTY_GETCONTENTLENGTH); - if (property != null) { - final String value = (String) property.getValue(); - return Long.parseLong(value); - } - return 0; - } - - /** - * Returns the last modified time of this file. Is only called if {@link #doGetType} does not return - * {@link FileType#IMAGINARY}. - */ - @Override - protected long doGetLastModifiedTime() throws Exception { - final DavProperty property = getProperty((GenericURLFileName) getName(), DavConstants.PROPERTY_GETLASTMODIFIED); - if (property != null) { - final String value = (String) property.getValue(); - return DateUtils.parseDate(value).getTime(); - } - return 0; - } - - @Override - protected OutputStream doGetOutputStream(final boolean bAppend) throws Exception { - return new WebdavOutputStream(this); - } - - /** - * Determines the type of this file. Must not return null. The return value of this method is cached, so the - * implementation can be expensive. - */ - @Override - protected FileType doGetType() throws Exception { - try { - return isDirectory((GenericURLFileName) getName()) ? FileType.FOLDER : FileType.FILE; - } catch (final FileNotFolderException | FileNotFoundException fnfe) { - return FileType.IMAGINARY; - } - - } - - /** - * Determines if this file can be written to. Is only called if {@link #doGetType} does not return - * {@link FileType#IMAGINARY}. - *

- * This implementation always returns true. - * - * @return true if the file is writable. - * @throws Exception if an error occurs. - */ - @Override - protected boolean doIsWriteable() throws Exception { - return true; - } - - /** - * Lists the children of the file. - */ - @Override - protected String[] doListChildren() throws Exception { - // use doListChildrenResolved for performance - return null; - } - - /** - * Lists the children of the file. - */ - @Override - protected FileObject[] doListChildrenResolved() throws Exception { - HttpPropfind request = null; - try { - final GenericURLFileName name = (GenericURLFileName) getName(); - if (isDirectory(name)) { - final DavPropertyNameSet nameSet = new DavPropertyNameSet(); - nameSet.add(DavPropertyName.create(DavConstants.PROPERTY_DISPLAYNAME)); - - request = new HttpPropfind(toUrlString(name), nameSet, DavConstants.DEPTH_1); - - try (CloseableHttpResponse res = (CloseableHttpResponse) executeRequest(request)) { - final List vfs = new ArrayList<>(); - if (request.succeeded(res)) { - final MultiStatusResponse[] responses = request.getResponseBodyAsMultiStatus(res).getResponses(); - - for (final MultiStatusResponse response : responses) { - if (isCurrentFile(response.getHref(), name)) { - continue; - } - final String resourceName = resourceName(response.getHref()); - if (!resourceName.isEmpty()) { - final Webdav4FileObject fo = (Webdav4FileObject) FileObjectUtils.getAbstractFileObject( - getFileSystem().resolveFile(getFileSystem().getFileSystemManager() - .resolveName(getName(), resourceName, NameScope.CHILD))); - vfs.add(fo); - } - } - } - return vfs.toArray(EMPTY_ARRAY); - } - } - throw new FileNotFolderException(getName()); - } catch (final FileNotFolderException fnfe) { - throw fnfe; - } catch (final DavException | IOException e) { - throw new FileSystemException(e.getMessage(), e); - } - } - - /** - * Rename the file. - */ - @Override - protected void doRename(final FileObject newFile) throws Exception { - final String url = toUrlString((GenericURLFileName) getName()); - final String dest = toUrlString((GenericURLFileName) newFile.getName(), false); - final HttpMove request = setupRequest(new HttpMove(url, dest, false)); - // AutoClose the underlying HTTP connection which is held by the response object - try (CloseableHttpResponse res = (CloseableHttpResponse) executeRequest(request)) { - // TODO: workaround due to PMD violation 'Empty try body - you could rename the resource to 'ignored' - request.succeeded(res); - } - } - - /** - * Sets an attribute of this file. Is only called if {@link #doGetType} does not return {@link FileType#IMAGINARY}. - */ - @Override - protected void doSetAttribute(final String attrName, final Object value) throws Exception { - try { - final GenericURLFileName fileName = (GenericURLFileName) getName(); - final String urlStr = toUrlString(fileName); - final DavPropertySet properties = new DavPropertySet(); - final DavPropertyNameSet propertyNameSet = new DavPropertyNameSet(); - final DavProperty property = new DefaultDavProperty<>(attrName, value, Namespace.EMPTY_NAMESPACE); - if (value != null) { - properties.add(property); - } else { - propertyNameSet.add(property.getName()); // remove property - } - - final HttpProppatch request = setupRequest(new HttpProppatch(urlStr, properties, propertyNameSet)); - // AutoClose the underlying HTTP connection which is held by the response object - try (CloseableHttpResponse response = (CloseableHttpResponse) executeRequest(request)) { - if (!request.succeeded(response)) { - throw new FileSystemException("Property '" + attrName + "' could not be set."); - } - } - } catch (final FileSystemException fse) { - throw fse; - } catch (final Exception e) { - throw new FileSystemException("vfs.provider.webdav/set-attributes", e, getName(), attrName); - } - } - - private HttpResponse executeRequest(final HttpUriRequest request) throws FileSystemException { - final HttpResponse response; - - try { - response = executeHttpUriRequest(request); - final int status = response.getStatusLine().getStatusCode(); - if (status == HttpURLConnection.HTTP_NOT_FOUND || status == HttpURLConnection.HTTP_GONE) { - EntityUtils.consume(response.getEntity()); - throw new FileNotFoundException(request.getURI()); - } - - if (request instanceof BaseDavRequest) { - ((BaseDavRequest) request).checkSuccess(response); - } - - return response; - } catch (final FileSystemException fse) { - throw fse; - } catch (final IOException e) { - throw new FileSystemException(e); - } catch (final DavException e) { - throw ExceptionConverter.generate(e); - } - } - - @Override - protected FileContentInfoFactory getFileContentInfoFactory() { - return new Webdav4FileContentInfoFactory(); - } - - DavPropertySet getProperties(final GenericURLFileName name) throws FileSystemException { - return getProperties(name, DavConstants.PROPFIND_ALL_PROP, new DavPropertyNameSet(), false); - } - - DavPropertySet getProperties(final GenericURLFileName name, final DavPropertyNameSet nameSet, final boolean addEncoding) - throws FileSystemException { - return getProperties(name, DavConstants.PROPFIND_BY_PROPERTY, nameSet, addEncoding); - } - - DavPropertySet getProperties(final GenericURLFileName name, final int type, final DavPropertyNameSet nameSet, - final boolean addEncoding) throws FileSystemException { - try { - final String urlStr = toUrlString(name); - final HttpPropfind request = setupRequest(new HttpPropfind(urlStr, type, nameSet, DavConstants.DEPTH_0)); - try (CloseableHttpResponse res = (CloseableHttpResponse) executeRequest(request)) { - if (request.succeeded(res)) { - final MultiStatus multiStatus = request.getResponseBodyAsMultiStatus(res); - final MultiStatusResponse response = multiStatus.getResponses()[0]; - final DavPropertySet props = response.getProperties(HttpStatus.SC_OK); - if (addEncoding) { - final ContentType resContentType = ContentType.getOrDefault(res.getEntity()); - final DavProperty prop = new DefaultDavProperty<>(RESPONSE_CHARSET, - resContentType.getCharset().name()); - props.add(prop); - } - return props; - } - return new DavPropertySet(); - } - } catch (final FileSystemException fse) { - throw fse; - } catch (final Exception e) { - throw new FileSystemException("vfs.provider.webdav/get-property.error", e, getName(), name, type, - nameSet.getContent(), addEncoding); - } - } - - DavProperty getProperty(final GenericURLFileName fileName, final DavPropertyName name) throws FileSystemException { - final DavPropertyNameSet nameSet = new DavPropertyNameSet(); - nameSet.add(name); - final DavPropertySet propertySet = getProperties(fileName, nameSet, false); - return propertySet.get(name); - } - - DavProperty getProperty(final GenericURLFileName fileName, final String property) throws FileSystemException { - return getProperty(fileName, DavPropertyName.create(property)); - } - - DavPropertySet getPropertyNames(final GenericURLFileName name) throws FileSystemException { - return getProperties(name, DavConstants.PROPFIND_PROPERTY_NAMES, new DavPropertyNameSet(), false); - } - - /** - * Convert the FileName to an encoded url String. - * - * @param name The FileName. - * @return The encoded URL String. - */ - private String hrefString(final GenericURLFileName name) { - try { - final GenericURLFileName newFile = new GenericURLFileName(getInternalURI().getScheme(), name.getHostName(), name.getPort(), name.getDefaultPort(), - null, null, name.getPath(), name.getType(), name.getQueryString()); - return newFile.getURIEncoded(getUrlCharset()); - } catch (final Exception e) { - return name.getURI(); - } - } - - private boolean isCurrentFile(final String href, final GenericURLFileName fileName) { - String name = hrefString(fileName); - if (href.endsWith("/") && !name.endsWith("/")) { - name += "/"; - } - return href.equals(name) || href.equals(fileName.getPath()); - } - - private boolean isDirectory(final GenericURLFileName name) throws IOException { - try { - final DavProperty property = getProperty(name, DavConstants.PROPERTY_RESOURCETYPE); - final Node node; - if (property != null && (node = (Node) property.getValue()) != null) { - return node.getLocalName().equals(DavConstants.XML_COLLECTION); - } - return false; - } catch (final FileNotFoundException fse) { - throw new FileNotFolderException(name); - } - } - - void log(final Exception ex) { - // TODO Consider logging - } - - /** - * Returns the resource name from the path. - * - * @param path the path to the file. - * @return The resource name - */ - private String resourceName(String path) { - if (path.endsWith("/")) { - path = path.substring(0, path.length() - 1); - } - final int i = path.lastIndexOf("/"); - return i >= 0 ? path.substring(i + 1) : path; - } - - private T setupRequest(final T request) { - // NOTE: *FileSystemConfigBuilder takes care of redirect option and user agent. - request.addHeader("Cache-control", "no-cache"); - request.addHeader("Cache-store", "no-store"); - request.addHeader("Pragma", "no-cache"); - request.addHeader("Expires", "0"); - return request; - } - - /** - * Converts the given URLFileName to an encoded URL String to internally use in real DAV operations. - * - * @param name The FileName. - * @return The encoded URL String. - */ - String toUrlString(final GenericURLFileName name) { - return toUrlString(name, true); - } - - /** - * Converts the given URLFileName to an encoded URL String to internally use in real DAV operations. - * - * @param name The FileName. - * @param includeUserInfo true if user information should be included. - * @return The encoded URL String. - */ - private String toUrlString(final GenericURLFileName name, final boolean includeUserInfo) { - String user = null; - String password = null; - if (includeUserInfo) { - user = name.getUserName(); - password = name.getPassword(); - } - try { - final GenericURLFileName newFile = new Webdav4FileName(getInternalURI().getScheme(), name.getHostName(), name.getPort(), name.getDefaultPort(), - user, password, name.getPath(), name.getType(), name.getQueryString(), - builder.getAppendTrailingSlash(getFileSystem().getFileSystemOptions())); - return newFile.getURIEncoded(getUrlCharset()); - } catch (final Exception e) { - return name.getURI(); - } - } -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.vfs2.provider.webdav4; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.vfs2.FileContentInfoFactory; +import org.apache.commons.vfs2.FileNotFolderException; +import org.apache.commons.vfs2.FileNotFoundException; +import org.apache.commons.vfs2.FileObject; +import org.apache.commons.vfs2.FileSystemException; +import org.apache.commons.vfs2.FileType; +import org.apache.commons.vfs2.NameScope; +import org.apache.commons.vfs2.provider.AbstractFileName; +import org.apache.commons.vfs2.provider.DefaultFileContent; +import org.apache.commons.vfs2.provider.GenericURLFileName; +import org.apache.commons.vfs2.provider.http4.Http4FileObject; +import org.apache.commons.vfs2.util.FileObjectUtils; +import org.apache.commons.vfs2.util.MonitorOutputStream; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPut; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.client.utils.DateUtils; +import org.apache.http.entity.ByteArrayEntity; +import org.apache.http.entity.ContentType; +import org.apache.http.util.EntityUtils; +import org.apache.jackrabbit.webdav.DavConstants; +import org.apache.jackrabbit.webdav.DavException; +import org.apache.jackrabbit.webdav.MultiStatus; +import org.apache.jackrabbit.webdav.MultiStatusResponse; +import org.apache.jackrabbit.webdav.client.methods.BaseDavRequest; +import org.apache.jackrabbit.webdav.client.methods.HttpCheckin; +import org.apache.jackrabbit.webdav.client.methods.HttpCheckout; +import org.apache.jackrabbit.webdav.client.methods.HttpDelete; +import org.apache.jackrabbit.webdav.client.methods.HttpMkcol; +import org.apache.jackrabbit.webdav.client.methods.HttpMove; +import org.apache.jackrabbit.webdav.client.methods.HttpPropfind; +import org.apache.jackrabbit.webdav.client.methods.HttpProppatch; +import org.apache.jackrabbit.webdav.client.methods.HttpVersionControl; +import org.apache.jackrabbit.webdav.property.DavProperty; +import org.apache.jackrabbit.webdav.property.DavPropertyName; +import org.apache.jackrabbit.webdav.property.DavPropertyNameSet; +import org.apache.jackrabbit.webdav.property.DavPropertySet; +import org.apache.jackrabbit.webdav.property.DefaultDavProperty; +import org.apache.jackrabbit.webdav.version.DeltaVConstants; +import org.apache.jackrabbit.webdav.version.VersionControlledResource; +import org.apache.jackrabbit.webdav.xml.Namespace; +import org.w3c.dom.Node; + +/** + * A WebDAV file. + * + * @since 2.5.0 + */ +public class Webdav4FileObject extends Http4FileObject { + + /** + * An OutputStream that writes to a WebDAV resource. + *

+ * TODO - Use piped stream to avoid temporary file. + *

+ */ + private class WebdavOutputStream extends MonitorOutputStream { + private final Webdav4FileObject file; + + WebdavOutputStream(final Webdav4FileObject file) { + super(new ByteArrayOutputStream()); + this.file = file; + } + + private boolean createVersion(final String urlStr) { + try { + final HttpVersionControl request = setupRequest(new HttpVersionControl(urlStr)); + // AutoClose the underlying HTTP connection which is held by the response object + try (CloseableHttpResponse unused = (CloseableHttpResponse) executeRequest(request)) { + return true; + } + } catch (final Exception ex) { + return false; + } + } + + /** + * Called after this stream is closed. + */ + @Override + protected void onClose() throws IOException { + final HttpEntity entity = new ByteArrayEntity(((ByteArrayOutputStream) out).toByteArray()); + final GenericURLFileName fileName = (GenericURLFileName) getName(); + final String urlStr = toUrlString(fileName); + if (builder.isVersioning(getFileSystem().getFileSystemOptions())) { + DavPropertySet set = null; + boolean fileExists = true; + boolean isCheckedIn = true; + try { + set = getPropertyNames(fileName); + } catch (final FileNotFoundException fnfe) { + fileExists = false; + } + if (fileExists && set != null) { + if (set.contains(VersionControlledResource.CHECKED_OUT)) { + isCheckedIn = false; + } else if (!set.contains(VersionControlledResource.CHECKED_IN)) { + DavProperty prop = set.get(VersionControlledResource.AUTO_VERSION); + if (prop != null) { + prop = getProperty(fileName, VersionControlledResource.AUTO_VERSION); + if (DeltaVConstants.XML_CHECKOUT_CHECKIN.equals(prop.getValue())) { + createVersion(urlStr); + } + } + } + } + if (fileExists && isCheckedIn) { + try { + final HttpCheckout request = setupRequest(new HttpCheckout(urlStr)); + // AutoClose the underlying HTTP connection which is held by the response object + try (CloseableHttpResponse unused = (CloseableHttpResponse) executeRequest(request)) { + isCheckedIn = false; + } + } catch (final FileSystemException ex) { + log(ex); + } + } + + try { + final HttpPut request = new HttpPut(urlStr); + request.setEntity(entity); + setupRequest(request); + // AutoClose the underlying HTTP connection which is held by the response object + try (CloseableHttpResponse unused = (CloseableHttpResponse) executeRequest(request)) { + setUserName(fileName, urlStr); + } + } catch (final FileSystemException ex) { + if (!isCheckedIn) { + try { + final HttpCheckin request = new HttpCheckin(urlStr); + setupRequest(request); + // AutoClose the underlying HTTP connection which is held by the response object + try (CloseableHttpResponse unused = (CloseableHttpResponse) executeRequest(request)) { + isCheckedIn = true; + } + } catch (final Exception e) { + // Going to throw original. + log(e); + } + throw ex; + } + } + if (!fileExists) { + createVersion(urlStr); + try { + final DavPropertySet props = getPropertyNames(fileName); + isCheckedIn = !props.contains(VersionControlledResource.CHECKED_OUT); + } catch (final FileNotFoundException fnfe) { + log(fnfe); + } + } + if (!isCheckedIn) { + final HttpCheckin request = new HttpCheckin(urlStr); + setupRequest(request); + // AutoClose the underlying HTTP connection which is held by the response object + try (CloseableHttpResponse unused = (CloseableHttpResponse) executeRequest(request)) { + isCheckedIn = true; + } + } + } else { + final HttpPut request = new HttpPut(urlStr); + request.setEntity(entity); + setupRequest(request); + // AutoClose the underlying HTTP connection which is held by the response object + try (CloseableHttpResponse unused = (CloseableHttpResponse) executeRequest(request)) { + try { + setUserName(fileName, urlStr); + } catch (final IOException e) { + // Unable to set the user name. + log(e); + } + } + } + ((DefaultFileContent) file.getContent()).resetAttributes(); + } + + private void setUserName(final GenericURLFileName fileName, final String urlStr) throws IOException { + final DavPropertySet setProperties = new DavPropertySet(); + final DavPropertyNameSet removeProperties = new DavPropertyNameSet(); + String name = builder.getCreatorName(getFileSystem().getFileSystemOptions()); + final String userName = fileName.getUserName(); + if (name == null) { + name = userName; + } else if (userName != null) { + final String comment = "Modified by user " + userName; + setProperties.add(new DefaultDavProperty<>(DeltaVConstants.COMMENT, comment)); + } + setProperties.add(new DefaultDavProperty<>(DeltaVConstants.CREATOR_DISPLAYNAME, name)); + final HttpProppatch request = setupRequest(new HttpProppatch(urlStr, setProperties, removeProperties)); + // AutoClose the underlying HTTP connection which is held by the response object + try (CloseableHttpResponse res = (CloseableHttpResponse) executeRequest(request)) { + // TODO: workaround due to PMD violation 'Empty try body - you could rename the resource to 'ignored' + request.succeeded(res); + } + } + } + + /** The character set property name. */ + public static final DavPropertyName RESPONSE_CHARSET = DavPropertyName.create("response-charset"); + + /** + * An empty immutable {@code Webdav4FileObject} array. + */ + private static final Webdav4FileObject[] EMPTY_ARRAY = {}; + + /** The FileSystemConfigBuilder */ + private final Webdav4FileSystemConfigBuilder builder; + + /** + * Constructs a new instance. + * + * @param name file name. + * @param fileSystem file system. + * @throws FileSystemException if any error occurs + */ + protected Webdav4FileObject(final AbstractFileName name, final Webdav4FileSystem fileSystem) + throws FileSystemException { + this(name, fileSystem, Webdav4FileSystemConfigBuilder.getInstance()); + } + + /** + * Constructs a new instance. + * + * @param name file name. + * @param fileSystem file system. + * @param builder builds the file system configuration. + * @throws FileSystemException if any error occurs + */ + protected Webdav4FileObject(final AbstractFileName name, final Webdav4FileSystem fileSystem, + final Webdav4FileSystemConfigBuilder builder) throws FileSystemException { + super(name, fileSystem, builder); + this.builder = builder; + } + + /** + * Creates this file as a folder. + */ + @Override + protected void doCreateFolder() throws Exception { + final HttpMkcol request = setupRequest(new HttpMkcol(toUrlString((GenericURLFileName) getName()))); + try { + // AutoClose the underlying HTTP connection which is held by the response object + try (CloseableHttpResponse res = (CloseableHttpResponse) executeRequest(request)) { + // TODO: workaround due to PMD violation 'Empty try body - you could rename the resource to 'ignored' + request.succeeded(res); + } + } catch (final FileSystemException fse) { + throw new FileSystemException("vfs.provider.webdav/create-collection.error", getName(), fse); + } + } + + /** + * Deletes the file. + */ + @Override + protected void doDelete() throws Exception { + final HttpDelete request = setupRequest(new HttpDelete(toUrlString((GenericURLFileName) getName()))); + // AutoClose the underlying HTTP connection which is held by the response object + try (CloseableHttpResponse res = (CloseableHttpResponse) executeRequest(request)) { + // TODO: workaround due to PMD violation 'Empty try body - you could rename the resource to 'ignored' + request.succeeded(res); + } + } + + /** + * Returns the properties of the Webdav resource. + */ + @Override + protected Map doGetAttributes() throws Exception { + final Map attributes = new HashMap<>(); + try { + final GenericURLFileName fileName = (GenericURLFileName) getName(); + DavPropertySet properties = getProperties(fileName, DavConstants.PROPFIND_ALL_PROP, + new DavPropertyNameSet(), false); + for (final DavProperty property : properties) { + attributes.put(property.getName().toString(), property.getValue()); + } + properties = getPropertyNames(fileName); + for (DavProperty property : properties) { + if (!attributes.containsKey(property.getName().getName())) { + property = getProperty(fileName, property.getName()); + if (property != null) { + final Object name = property.getName(); + final Object value = property.getValue(); + if (name != null && value != null) { + attributes.put(name.toString(), value); + } + } + } + } + return attributes; + } catch (final Exception e) { + throw new FileSystemException("vfs.provider.webdav/get-attributes.error", getName(), e); + } + } + + /** + * Returns the size of the file content (in bytes). + */ + @Override + protected long doGetContentSize() throws Exception { + final DavProperty property = getProperty((GenericURLFileName) getName(), DavConstants.PROPERTY_GETCONTENTLENGTH); + if (property != null) { + final String value = (String) property.getValue(); + return Long.parseLong(value); + } + return 0; + } + + /** + * Returns the last modified time of this file. Is only called if {@link #doGetType} does not return + * {@link FileType#IMAGINARY}. + */ + @Override + protected long doGetLastModifiedTime() throws Exception { + final DavProperty property = getProperty((GenericURLFileName) getName(), DavConstants.PROPERTY_GETLASTMODIFIED); + if (property != null) { + final String value = (String) property.getValue(); + return DateUtils.parseDate(value).getTime(); + } + return 0; + } + + @Override + protected OutputStream doGetOutputStream(final boolean bAppend) throws Exception { + return new WebdavOutputStream(this); + } + + /** + * Determines the type of this file. Must not return null. The return value of this method is cached, so the + * implementation can be expensive. + */ + @Override + protected FileType doGetType() throws Exception { + try { + return isDirectory((GenericURLFileName) getName()) ? FileType.FOLDER : FileType.FILE; + } catch (final FileNotFolderException | FileNotFoundException fnfe) { + return FileType.IMAGINARY; + } + + } + + /** + * Determines if this file can be written to. Is only called if {@link #doGetType} does not return + * {@link FileType#IMAGINARY}. + *

+ * This implementation always returns true. + * + * @return true if the file is writable. + * @throws Exception if an error occurs. + */ + @Override + protected boolean doIsWriteable() throws Exception { + return true; + } + + /** + * Lists the children of the file. + */ + @Override + protected String[] doListChildren() throws Exception { + // use doListChildrenResolved for performance + return null; + } + + /** + * Lists the children of the file. + */ + @Override + protected FileObject[] doListChildrenResolved() throws Exception { + HttpPropfind request = null; + try { + final GenericURLFileName name = (GenericURLFileName) getName(); + if (isDirectory(name)) { + final DavPropertyNameSet nameSet = new DavPropertyNameSet(); + nameSet.add(DavPropertyName.create(DavConstants.PROPERTY_DISPLAYNAME)); + + request = new HttpPropfind(toUrlString(name), nameSet, DavConstants.DEPTH_1); + + try (CloseableHttpResponse res = (CloseableHttpResponse) executeRequest(request)) { + final List vfs = new ArrayList<>(); + if (request.succeeded(res)) { + final MultiStatusResponse[] responses = request.getResponseBodyAsMultiStatus(res).getResponses(); + + for (final MultiStatusResponse response : responses) { + if (isCurrentFile(response.getHref(), name)) { + continue; + } + final String resourceName = resourceName(response.getHref()); + if (!resourceName.isEmpty()) { + final Webdav4FileObject fo = (Webdav4FileObject) FileObjectUtils.getAbstractFileObject( + getFileSystem().resolveFile(getFileSystem().getFileSystemManager() + .resolveName(getName(), resourceName, NameScope.CHILD))); + vfs.add(fo); + } + } + } + return vfs.toArray(EMPTY_ARRAY); + } + } + throw new FileNotFolderException(getName()); + } catch (final FileNotFolderException fnfe) { + throw fnfe; + } catch (final DavException | IOException e) { + throw new FileSystemException(e.getMessage(), e); + } + } + + /** + * Rename the file. + */ + @Override + protected void doRename(final FileObject newFile) throws Exception { + final String url = toUrlString((GenericURLFileName) getName()); + final String dest = toUrlString((GenericURLFileName) newFile.getName(), false); + final HttpMove request = setupRequest(new HttpMove(url, dest, false)); + // AutoClose the underlying HTTP connection which is held by the response object + try (CloseableHttpResponse res = (CloseableHttpResponse) executeRequest(request)) { + // TODO: workaround due to PMD violation 'Empty try body - you could rename the resource to 'ignored' + request.succeeded(res); + } + } + + /** + * Sets an attribute of this file. Is only called if {@link #doGetType} does not return {@link FileType#IMAGINARY}. + */ + @Override + protected void doSetAttribute(final String attrName, final Object value) throws Exception { + try { + final GenericURLFileName fileName = (GenericURLFileName) getName(); + final String urlStr = toUrlString(fileName); + final DavPropertySet properties = new DavPropertySet(); + final DavPropertyNameSet propertyNameSet = new DavPropertyNameSet(); + final DavProperty property = new DefaultDavProperty<>(attrName, value, Namespace.EMPTY_NAMESPACE); + if (value != null) { + properties.add(property); + } else { + propertyNameSet.add(property.getName()); // remove property + } + + final HttpProppatch request = setupRequest(new HttpProppatch(urlStr, properties, propertyNameSet)); + // AutoClose the underlying HTTP connection which is held by the response object + try (CloseableHttpResponse response = (CloseableHttpResponse) executeRequest(request)) { + if (!request.succeeded(response)) { + throw new FileSystemException("Property '" + attrName + "' could not be set."); + } + } + } catch (final FileSystemException fse) { + throw fse; + } catch (final Exception e) { + throw new FileSystemException("vfs.provider.webdav/set-attributes", e, getName(), attrName); + } + } + + private HttpResponse executeRequest(final HttpUriRequest request) throws FileSystemException { + final HttpResponse response; + + try { + response = executeHttpUriRequest(request); + final int status = response.getStatusLine().getStatusCode(); + if (status == HttpURLConnection.HTTP_NOT_FOUND || status == HttpURLConnection.HTTP_GONE) { + EntityUtils.consume(response.getEntity()); + throw new FileNotFoundException(request.getURI()); + } + + if (request instanceof BaseDavRequest) { + ((BaseDavRequest) request).checkSuccess(response); + } + + return response; + } catch (final FileSystemException fse) { + throw fse; + } catch (final IOException e) { + throw new FileSystemException(e); + } catch (final DavException e) { + throw ExceptionConverter.generate(e); + } + } + + @Override + protected FileContentInfoFactory getFileContentInfoFactory() { + return new Webdav4FileContentInfoFactory(); + } + + DavPropertySet getProperties(final GenericURLFileName name) throws FileSystemException { + return getProperties(name, DavConstants.PROPFIND_ALL_PROP, new DavPropertyNameSet(), false); + } + + DavPropertySet getProperties(final GenericURLFileName name, final DavPropertyNameSet nameSet, final boolean addEncoding) + throws FileSystemException { + return getProperties(name, DavConstants.PROPFIND_BY_PROPERTY, nameSet, addEncoding); + } + + DavPropertySet getProperties(final GenericURLFileName name, final int type, final DavPropertyNameSet nameSet, + final boolean addEncoding) throws FileSystemException { + try { + final String urlStr = toUrlString(name); + final HttpPropfind request = setupRequest(new HttpPropfind(urlStr, type, nameSet, DavConstants.DEPTH_0)); + try (CloseableHttpResponse res = (CloseableHttpResponse) executeRequest(request)) { + if (request.succeeded(res)) { + final MultiStatus multiStatus = request.getResponseBodyAsMultiStatus(res); + final MultiStatusResponse response = multiStatus.getResponses()[0]; + final DavPropertySet props = response.getProperties(HttpStatus.SC_OK); + if (addEncoding) { + final ContentType resContentType = ContentType.getOrDefault(res.getEntity()); + final DavProperty prop = new DefaultDavProperty<>(RESPONSE_CHARSET, + resContentType.getCharset().name()); + props.add(prop); + } + return props; + } + return new DavPropertySet(); + } + } catch (final FileSystemException fse) { + throw fse; + } catch (final Exception e) { + throw new FileSystemException("vfs.provider.webdav/get-property.error", e, getName(), name, type, + nameSet.getContent(), addEncoding); + } + } + + DavProperty getProperty(final GenericURLFileName fileName, final DavPropertyName name) throws FileSystemException { + final DavPropertyNameSet nameSet = new DavPropertyNameSet(); + nameSet.add(name); + final DavPropertySet propertySet = getProperties(fileName, nameSet, false); + return propertySet.get(name); + } + + DavProperty getProperty(final GenericURLFileName fileName, final String property) throws FileSystemException { + return getProperty(fileName, DavPropertyName.create(property)); + } + + DavPropertySet getPropertyNames(final GenericURLFileName name) throws FileSystemException { + return getProperties(name, DavConstants.PROPFIND_PROPERTY_NAMES, new DavPropertyNameSet(), false); + } + + /** + * Convert the FileName to an encoded url String. + * + * @param name The FileName. + * @return The encoded URL String. + */ + private String hrefString(final GenericURLFileName name) { + try { + final GenericURLFileName newFile = new GenericURLFileName(getInternalURI().getScheme(), name.getHostName(), name.getPort(), name.getDefaultPort(), + null, null, name.getPath(), name.getType(), name.getQueryString()); + return newFile.getURIEncoded(getUrlCharset()); + } catch (final Exception e) { + return name.getURI(); + } + } + + private boolean isCurrentFile(final String href, final GenericURLFileName fileName) { + String name = hrefString(fileName); + if (href.endsWith("/") && !name.endsWith("/")) { + name += "/"; + } + return href.equals(name) || href.equals(fileName.getPath()); + } + + private boolean isDirectory(final GenericURLFileName name) throws IOException { + try { + final DavProperty property = getProperty(name, DavConstants.PROPERTY_RESOURCETYPE); + final Node node; + if (property != null && (node = (Node) property.getValue()) != null) { + return node.getLocalName().equals(DavConstants.XML_COLLECTION); + } + return false; + } catch (final FileNotFoundException fse) { + throw new FileNotFolderException(name); + } + } + + void log(final Exception ex) { + // TODO Consider logging + } + + /** + * Returns the resource name from the path. + * + * @param path the path to the file. + * @return The resource name + */ + private String resourceName(String path) { + if (path.endsWith("/")) { + path = path.substring(0, path.length() - 1); + } + final int i = path.lastIndexOf("/"); + return i >= 0 ? path.substring(i + 1) : path; + } + + private T setupRequest(final T request) { + // NOTE: *FileSystemConfigBuilder takes care of redirect option and user agent. + request.addHeader("Cache-control", "no-cache"); + request.addHeader("Cache-store", "no-store"); + request.addHeader("Pragma", "no-cache"); + request.addHeader("Expires", "0"); + return request; + } + + /** + * Converts the given URLFileName to an encoded URL String to internally use in real DAV operations. + * + * @param name The FileName. + * @return The encoded URL String. + */ + String toUrlString(final GenericURLFileName name) { + return toUrlString(name, true); + } + + /** + * Converts the given URLFileName to an encoded URL String to internally use in real DAV operations. + * + * @param name The FileName. + * @param includeUserInfo true if user information should be included. + * @return The encoded URL String. + */ + private String toUrlString(final GenericURLFileName name, final boolean includeUserInfo) { + String user = null; + String password = null; + if (includeUserInfo) { + user = name.getUserName(); + password = name.getPassword(); + } + try { + final GenericURLFileName newFile = new Webdav4FileName(getInternalURI().getScheme(), name.getHostName(), name.getPort(), name.getDefaultPort(), + user, password, name.getPath(), name.getType(), name.getQueryString(), + builder.getAppendTrailingSlash(getFileSystem().getFileSystemOptions())); + return newFile.getURIEncoded(getUrlCharset()); + } catch (final Exception e) { + return name.getURI(); + } + } +} diff --git a/commons-vfs2-jackrabbit2/src/test/resources/test-data/read-xml-tests/address.xsd b/commons-vfs2-jackrabbit2/src/test/resources/test-data/read-xml-tests/address.xsd index 065648abcd..81309a9670 100644 --- a/commons-vfs2-jackrabbit2/src/test/resources/test-data/read-xml-tests/address.xsd +++ b/commons-vfs2-jackrabbit2/src/test/resources/test-data/read-xml-tests/address.xsd @@ -1,45 +1,45 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + diff --git a/commons-vfs2-jackrabbit2/src/test/resources/test-data/read-xml-tests/file1.xml b/commons-vfs2-jackrabbit2/src/test/resources/test-data/read-xml-tests/file1.xml index 42e9846ec7..c7ef3698db 100644 --- a/commons-vfs2-jackrabbit2/src/test/resources/test-data/read-xml-tests/file1.xml +++ b/commons-vfs2-jackrabbit2/src/test/resources/test-data/read-xml-tests/file1.xml @@ -1,18 +1,18 @@ - - -foo1 + + +foo1 diff --git a/commons-vfs2-jackrabbit2/src/test/resources/test-data/read-xml-tests/file2.xml b/commons-vfs2-jackrabbit2/src/test/resources/test-data/read-xml-tests/file2.xml index 2e3ff38237..78cb379bfc 100644 --- a/commons-vfs2-jackrabbit2/src/test/resources/test-data/read-xml-tests/file2.xml +++ b/commons-vfs2-jackrabbit2/src/test/resources/test-data/read-xml-tests/file2.xml @@ -1,18 +1,18 @@ - - -foo2 + + +foo2 diff --git a/commons-vfs2-jackrabbit2/src/test/resources/test-data/read-xml-tests/file3-bigger.xml b/commons-vfs2-jackrabbit2/src/test/resources/test-data/read-xml-tests/file3-bigger.xml index 780dc4860c..53e655cae6 100644 --- a/commons-vfs2-jackrabbit2/src/test/resources/test-data/read-xml-tests/file3-bigger.xml +++ b/commons-vfs2-jackrabbit2/src/test/resources/test-data/read-xml-tests/file3-bigger.xml @@ -1,1354 +1,1354 @@ - - - - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - + + + + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + diff --git a/commons-vfs2-jackrabbit2/src/test/resources/test-data/read-xml-tests/name-invalid.xml b/commons-vfs2-jackrabbit2/src/test/resources/test-data/read-xml-tests/name-invalid.xml index 522c4f6f3f..8c3f9f327c 100644 --- a/commons-vfs2-jackrabbit2/src/test/resources/test-data/read-xml-tests/name-invalid.xml +++ b/commons-vfs2-jackrabbit2/src/test/resources/test-data/read-xml-tests/name-invalid.xml @@ -1,25 +1,25 @@ - - - - John - Q. - Public - + + + + John + Q. + Public + diff --git a/commons-vfs2-jackrabbit2/src/test/resources/test-data/read-xml-tests/name-not-well-formed.xml b/commons-vfs2-jackrabbit2/src/test/resources/test-data/read-xml-tests/name-not-well-formed.xml index 305ac6eba8..31dbdd1bb4 100644 --- a/commons-vfs2-jackrabbit2/src/test/resources/test-data/read-xml-tests/name-not-well-formed.xml +++ b/commons-vfs2-jackrabbit2/src/test/resources/test-data/read-xml-tests/name-not-well-formed.xml @@ -1,24 +1,24 @@ - - - - John - Q. - Public + + + + John + Q. + Public diff --git a/commons-vfs2-jackrabbit2/src/test/resources/test-data/read-xml-tests/name-with-xsd-ref.xml b/commons-vfs2-jackrabbit2/src/test/resources/test-data/read-xml-tests/name-with-xsd-ref.xml index cad2771282..e2f171c010 100644 --- a/commons-vfs2-jackrabbit2/src/test/resources/test-data/read-xml-tests/name-with-xsd-ref.xml +++ b/commons-vfs2-jackrabbit2/src/test/resources/test-data/read-xml-tests/name-with-xsd-ref.xml @@ -1,25 +1,25 @@ - - - - John - Q. - Public - + + + + John + Q. + Public + diff --git a/commons-vfs2-jackrabbit2/src/test/resources/test-data/read-xml-tests/name.xml b/commons-vfs2-jackrabbit2/src/test/resources/test-data/read-xml-tests/name.xml index 4c5c870722..fb60df3b55 100644 --- a/commons-vfs2-jackrabbit2/src/test/resources/test-data/read-xml-tests/name.xml +++ b/commons-vfs2-jackrabbit2/src/test/resources/test-data/read-xml-tests/name.xml @@ -1,22 +1,22 @@ - - - - John - Q. - Public - + + + + John + Q. + Public + diff --git a/commons-vfs2-jackrabbit2/src/test/resources/test-data/read-xml-tests/name.xsd b/commons-vfs2-jackrabbit2/src/test/resources/test-data/read-xml-tests/name.xsd index 9b0a6a7193..98611639ff 100644 --- a/commons-vfs2-jackrabbit2/src/test/resources/test-data/read-xml-tests/name.xsd +++ b/commons-vfs2-jackrabbit2/src/test/resources/test-data/read-xml-tests/name.xsd @@ -1,42 +1,42 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/commons-vfs2-jackrabbit2/src/test/resources/test-data/read-xml-tests/person.xml b/commons-vfs2-jackrabbit2/src/test/resources/test-data/read-xml-tests/person.xml index 28e023f633..1b375b84c0 100644 --- a/commons-vfs2-jackrabbit2/src/test/resources/test-data/read-xml-tests/person.xml +++ b/commons-vfs2-jackrabbit2/src/test/resources/test-data/read-xml-tests/person.xml @@ -1,38 +1,38 @@ - - - - - - John - Q. - Public - - - - 123 Main St. - Ridgway - CO - 81432 - - - + + + + + + John + Q. + Public + + + + 123 Main St. + Ridgway + CO + 81432 + + + diff --git a/commons-vfs2-jackrabbit2/src/test/resources/test-data/read-xml-tests/person.xsd b/commons-vfs2-jackrabbit2/src/test/resources/test-data/read-xml-tests/person.xsd index 4bc82a9408..8c43bd84fe 100644 --- a/commons-vfs2-jackrabbit2/src/test/resources/test-data/read-xml-tests/person.xsd +++ b/commons-vfs2-jackrabbit2/src/test/resources/test-data/read-xml-tests/person.xsd @@ -1,48 +1,48 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + diff --git a/commons-vfs2-sandbox/src/site/xdoc/index.xml b/commons-vfs2-sandbox/src/site/xdoc/index.xml index c0d12b9d81..b9337a71c9 100644 --- a/commons-vfs2-sandbox/src/site/xdoc/index.xml +++ b/commons-vfs2-sandbox/src/site/xdoc/index.xml @@ -1,47 +1,47 @@ - - - - - - Apache Commons VFS Sandbox - Apache Commons Developers - - - - -
-

- This sandbox module contains VFS packages (filesystem - providers) which cannot be shipped with the official Apache release. - This includes experimental code as well as components which have - dependencies not compatible with the - ASF redistribution policy - (especially LGPL). -

- To build the sandbox binaries, see the download and build - instructions. - Make sure to enable the sandbox maven profile with -Pinclude-sandbox. - If you use mvn install the sandbox binary archive can be used from - the local repository. If you are not using the released source archive, you may have - to adjust the parent-version and version-numbers if you want to avoid SNAPSHOT - artifacts. -

-
- - -
+ + + + + + Apache Commons VFS Sandbox + Apache Commons Developers + + + + +
+

+ This sandbox module contains VFS packages (filesystem + providers) which cannot be shipped with the official Apache release. + This includes experimental code as well as components which have + dependencies not compatible with the + ASF redistribution policy + (especially LGPL). +

+ To build the sandbox binaries, see the download and build + instructions. + Make sure to enable the sandbox maven profile with -Pinclude-sandbox. + If you use mvn install the sandbox binary archive can be used from + the local repository. If you are not using the released source archive, you may have + to adjust the parent-version and version-numbers if you want to avoid SNAPSHOT + artifacts. +

+
+ + +
diff --git a/commons-vfs2/pom.xml b/commons-vfs2/pom.xml index 5f6aaa4241..c7edd70946 100644 --- a/commons-vfs2/pom.xml +++ b/commons-vfs2/pom.xml @@ -1,424 +1,424 @@ - - - - - - - 4.0.0 - - Apache Commons VFS - commons-vfs2 - jar - Apache Commons VFS is a Virtual File System library. - https://commons.apache.org/proper/commons-vfs/ - - - org.apache.commons - commons-vfs2-project - 2.10.0-SNAPSHOT - ../pom.xml - - - - - commons-logging - commons-logging - - - commons-net - commons-net - true - - - org.apache.commons - commons-compress - true - - - org.apache.commons - commons-collections4 - true - - - commons-httpclient - commons-httpclient - true - - - org.apache.httpcomponents - httpclient - true - - - org.apache.httpcomponents.core5 - httpcore5 - true - - - org.apache.httpcomponents.client5 - httpclient5 - true - - - com.jcraft - jsch - true - - - - org.junit.jupiter - junit-jupiter - test - - - org.junit.vintage - junit-vintage-engine - test - - - org.mockito - mockito-core - test - - - org.apache.commons - commons-lang3 - - - - org.apache.ftpserver - ftpserver-core - test - - - org.slf4j - slf4j-api - test - - - org.apache.logging.log4j - log4j-slf4j-impl - test - - - org.apache.logging.log4j - log4j-core - test - - - - org.apache.sshd - sshd-core - test - - - org.bouncycastle - bcprov-jdk16 - test - - - commons-io - commons-io - - - - org.apache.httpcomponents - httpcore-nio - test - - - - org.openjdk.jmh - jmh-core - test - - - - - ${basedir}/.. - - org.apache.hc.client5.http.*;resolution:=optional, - * - - 2024-03-03T15:45:26Z - - - - - - - - - - - ${basedir}/src/main/resources - - - - ${commons.parent.dir} - META-INF - - NOTICE.txt - LICENSE.txt - - - - - - - src/test/resources - - - - ${commons.parent.dir} - META-INF - - NOTICE.txt - LICENSE.txt - - - - - - - org.apache.maven.plugins - maven-jar-plugin - - - - test-jar - - - - - - - org.apache.maven.plugins - maven-antrun-plugin - - - process-test-classes - - - - - - - - - run - - - - - - - org.apache.maven.plugins - maven-surefire-plugin - - false - - target/test-classes/test-data - test-data - target/derby.log - - - - **/RunTest.java - - **/*$* - - - **/*Tests.java - - - - - - - - - webdav - - false - - - - - org.apache.maven.plugins - maven-surefire-plugin - - - ${test.webdav.uri} - - - - - - - - - ftp - - false - - - - - org.apache.maven.plugins - maven-surefire-plugin - - - ${test.ftp.uri} - - - - - - - - - sftp - - false - - - - - org.apache.maven.plugins - maven-surefire-plugin - - - ${test.sftp.uri} - - - - - - - - - http - - false - - - - - org.apache.maven.plugins - maven-surefire-plugin - - - ${test.http.uri} - - - - - - - - - - no-test-hdfs - - false - - Windows - - - - - - org.apache.maven.plugins - maven-surefire-plugin - - - **/HdfsFileProviderTest.java - **/HdfsFileProviderTestCase.java - - - **/*Tests.java - - - - - - - - - benchmark - - - true - org.apache - - - - - org.openjdk.jmh - jmh-generator-annprocess - test - - - - - - - - maven-compiler-plugin - ${commons.compiler.version} - - - **/* - - - - - - org.codehaus.mojo - exec-maven-plugin - - - benchmark - test - - exec - - - test - java - - -classpath - - org.openjdk.jmh.Main - -rf - json - -rff - target/jmh-result.json - ${benchmark} - - - - - - - - - - - + + + + + + + 4.0.0 + + Apache Commons VFS + commons-vfs2 + jar + Apache Commons VFS is a Virtual File System library. + https://commons.apache.org/proper/commons-vfs/ + + + org.apache.commons + commons-vfs2-project + 2.10.0-SNAPSHOT + ../pom.xml + + + + + commons-logging + commons-logging + + + commons-net + commons-net + true + + + org.apache.commons + commons-compress + true + + + org.apache.commons + commons-collections4 + true + + + commons-httpclient + commons-httpclient + true + + + org.apache.httpcomponents + httpclient + true + + + org.apache.httpcomponents.core5 + httpcore5 + true + + + org.apache.httpcomponents.client5 + httpclient5 + true + + + com.jcraft + jsch + true + + + + org.junit.jupiter + junit-jupiter + test + + + org.junit.vintage + junit-vintage-engine + test + + + org.mockito + mockito-core + test + + + org.apache.commons + commons-lang3 + + + + org.apache.ftpserver + ftpserver-core + test + + + org.slf4j + slf4j-api + test + + + org.apache.logging.log4j + log4j-slf4j-impl + test + + + org.apache.logging.log4j + log4j-core + test + + + + org.apache.sshd + sshd-core + test + + + org.bouncycastle + bcprov-jdk16 + test + + + commons-io + commons-io + + + + org.apache.httpcomponents + httpcore-nio + test + + + + org.openjdk.jmh + jmh-core + test + + + + + ${basedir}/.. + + org.apache.hc.client5.http.*;resolution:=optional, + * + + 2024-03-03T15:45:26Z + + + + + + + + + + + ${basedir}/src/main/resources + + + + ${commons.parent.dir} + META-INF + + NOTICE.txt + LICENSE.txt + + + + + + + src/test/resources + + + + ${commons.parent.dir} + META-INF + + NOTICE.txt + LICENSE.txt + + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + + test-jar + + + + + + + org.apache.maven.plugins + maven-antrun-plugin + + + process-test-classes + + + + + + + + + run + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + false + + target/test-classes/test-data + test-data + target/derby.log + + + + **/RunTest.java + + **/*$* + + + **/*Tests.java + + + + + + + + + webdav + + false + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + ${test.webdav.uri} + + + + + + + + + ftp + + false + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + ${test.ftp.uri} + + + + + + + + + sftp + + false + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + ${test.sftp.uri} + + + + + + + + + http + + false + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + ${test.http.uri} + + + + + + + + + + no-test-hdfs + + false + + Windows + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + **/HdfsFileProviderTest.java + **/HdfsFileProviderTestCase.java + + + **/*Tests.java + + + + + + + + + benchmark + + + true + org.apache + + + + + org.openjdk.jmh + jmh-generator-annprocess + test + + + + + + + + maven-compiler-plugin + ${commons.compiler.version} + + + **/* + + + + + + org.codehaus.mojo + exec-maven-plugin + + + benchmark + test + + exec + + + test + java + + -classpath + + org.openjdk.jmh.Main + -rf + json + -rff + target/jmh-result.json + ${benchmark} + + + + + + + + + + + diff --git a/commons-vfs2/src/main/java/org/apache/commons/vfs2/impl/StandardFileSystemManager.java b/commons-vfs2/src/main/java/org/apache/commons/vfs2/impl/StandardFileSystemManager.java index d018e3c2a1..bacbad825f 100644 --- a/commons-vfs2/src/main/java/org/apache/commons/vfs2/impl/StandardFileSystemManager.java +++ b/commons-vfs2/src/main/java/org/apache/commons/vfs2/impl/StandardFileSystemManager.java @@ -1,445 +1,445 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.vfs2.impl; - -import java.io.IOException; -import java.io.InputStream; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.Objects; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; - -import org.apache.commons.lang3.ArrayUtils; -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.vfs2.FileSystemException; -import org.apache.commons.vfs2.VfsLog; -import org.apache.commons.vfs2.operations.FileOperationProvider; -import org.apache.commons.vfs2.provider.FileProvider; -import org.apache.commons.vfs2.util.Messages; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; - -/** - * A {@link org.apache.commons.vfs2.FileSystemManager} that configures itself from an XML (Default: providers.xml) - * configuration file. - *

- * Certain providers are only loaded and available if the dependent library is in your classpath. You have to configure - * your debugging facility to log "debug" messages to see if a provider was skipped due to "unresolved externals". - *

- */ -public class StandardFileSystemManager extends DefaultFileSystemManager { - private static final String CONFIG_RESOURCE = "providers.xml"; - private static final String PLUGIN_CONFIG_RESOURCE = "META-INF/vfs-providers.xml"; - - private URL configUri; - private ClassLoader classLoader; - - /** - * Constructs a new instance. - */ - public StandardFileSystemManager() { - // empty - } - - /** - * Adds an extension map. - * - * @param map containing the Elements. - */ - private void addExtensionMap(final Element map) { - final String extension = map.getAttribute("extension"); - final String scheme = map.getAttribute("scheme"); - if (!StringUtils.isEmpty(scheme)) { - addExtensionMap(extension, scheme); - } - } - - /** - * Adds a mime-type map. - * - * @param map containing the Elements. - */ - private void addMimeTypeMap(final Element map) { - final String mimeType = map.getAttribute("mime-type"); - final String scheme = map.getAttribute("scheme"); - addMimeTypeMap(mimeType, scheme); - } - - /** - * Adds a operationProvider from a operationProvider definition. - */ - private void addOperationProvider(final Element providerDef) throws FileSystemException { - final String className = providerDef.getAttribute("class-name"); - - // Attach only to available schemas - final String[] schemas = getSchemas(providerDef); - for (final String schema : schemas) { - if (hasProvider(schema)) { - final FileOperationProvider operationProvider = (FileOperationProvider) createInstance(className); - addOperationProvider(schema, operationProvider); - } - } - } - - /** - * Adds a provider from a provider definition. - * - * @param providerDef the provider definition - * @param isDefault true if the default should be used. - * @throws FileSystemException if an error occurs. - */ - private void addProvider(final Element providerDef, final boolean isDefault) throws FileSystemException { - final String className = providerDef.getAttribute("class-name"); - - // Make sure all required schemes are available - final String[] requiredSchemes = getRequiredSchemes(providerDef); - for (final String requiredScheme : requiredSchemes) { - if (!hasProvider(requiredScheme)) { - final String msg = Messages.getString("vfs.impl/skipping-provider-scheme.debug", className, - requiredScheme); - VfsLog.debug(getLogger(), getLogger(), msg); - return; - } - } - - // Make sure all required classes are in classpath - final String[] requiredClasses = getRequiredClasses(providerDef); - for (final String requiredClass : requiredClasses) { - if (!findClass(requiredClass)) { - final String msg = Messages.getString("vfs.impl/skipping-provider.debug", className, requiredClass); - VfsLog.debug(getLogger(), getLogger(), msg); - return; - } - } - - // Create and register the provider - final FileProvider provider = (FileProvider) createInstance(className); - final String[] schemas = getSchemas(providerDef); - if (schemas.length > 0) { - addProvider(schemas, provider); - } - - // Set as default, if required - if (isDefault) { - setDefaultProvider(provider); - } - } - - /** - * Configures this manager from a parsed XML configuration file - * - * @param config The configuration Element. - * @throws FileSystemException if an error occurs. - */ - private void configure(final Element config) throws FileSystemException { - // Add the providers - final NodeList providers = config.getElementsByTagName("provider"); - final int count = providers.getLength(); - for (int i = 0; i < count; i++) { - final Element provider = (Element) providers.item(i); - addProvider(provider, false); - } - - // Add the operation providers - final NodeList operationProviders = config.getElementsByTagName("operationProvider"); - for (int i = 0; i < operationProviders.getLength(); i++) { - final Element operationProvider = (Element) operationProviders.item(i); - addOperationProvider(operationProvider); - } - - // Add the default provider - final NodeList defProviders = config.getElementsByTagName("default-provider"); - if (defProviders.getLength() > 0) { - final Element provider = (Element) defProviders.item(0); - addProvider(provider, true); - } - - // Add the mime-type maps - final NodeList mimeTypes = config.getElementsByTagName("mime-type-map"); - for (int i = 0; i < mimeTypes.getLength(); i++) { - final Element map = (Element) mimeTypes.item(i); - addMimeTypeMap(map); - } - - // Add the extension maps - final NodeList extensions = config.getElementsByTagName("extension-map"); - for (int i = 0; i < extensions.getLength(); i++) { - final Element map = (Element) extensions.item(i); - addExtensionMap(map); - } - } - - /** - * Configures this manager from an XML configuration file. - * - * @param configUri The URI of the configuration. - * @throws FileSystemException if an error occurs. - */ - private void configure(final URL configUri) throws FileSystemException { - InputStream configStream = null; - try { - // Load up the config - // TODO - validate - final DocumentBuilder builder = createDocumentBuilder(); - configStream = configUri.openStream(); - final Element config = builder.parse(configStream).getDocumentElement(); - - configure(config); - } catch (final Exception e) { - throw new FileSystemException("vfs.impl/load-config.error", configUri.toString(), e); - } finally { - if (configStream != null) { - try { - configStream.close(); - } catch (final IOException e) { - getLogger().warn(e.getLocalizedMessage(), e); - } - } - } - } - - /** - * Scans the classpath to find any dropped plugin. - *

- * The plugin-description has to be in {@code /META-INF/vfs-providers.xml}. - *

- * - * @throws FileSystemException if an error occurs. - */ - protected void configurePlugins() throws FileSystemException { - final Enumeration enumResources; - try { - enumResources = enumerateResources(PLUGIN_CONFIG_RESOURCE); - } catch (final IOException e) { - throw new FileSystemException(e); - } - - while (enumResources.hasMoreElements()) { - configure(enumResources.nextElement()); - } - } - - /** - * Gets a new DefaultFileReplicator. - * - * @return a new DefaultFileReplicator. - */ - protected DefaultFileReplicator createDefaultFileReplicator() { - return new DefaultFileReplicator(); - } - - /** - * Configure and create a DocumentBuilder - * - * @return A DocumentBuilder for the configuration. - * @throws ParserConfigurationException if an error occurs. - */ - private DocumentBuilder createDocumentBuilder() throws ParserConfigurationException { - final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setIgnoringElementContentWhitespace(true); - factory.setIgnoringComments(true); - factory.setExpandEntityReferences(true); - return factory.newDocumentBuilder(); - } - - /** - * Creates a provider. - */ - private Object createInstance(final String className) throws FileSystemException { - try { - return loadClass(className).getConstructor().newInstance(); - } catch (final Exception e) { - throw new FileSystemException("vfs.impl/create-provider.error", className, e); - } - } - - /** - * Enumerates resources from different class loaders. - * - * @throws IOException if {@code getResource} failed. - * @see #findClassLoader() - */ - private Enumeration enumerateResources(final String name) throws IOException { - Enumeration enumeration = findClassLoader().getResources(name); - if (enumeration == null || !enumeration.hasMoreElements()) { - enumeration = getValidClassLoader(getClass()).getResources(name); - } - return enumeration; - } - - /** - * Tests if a class is available. - */ - private boolean findClass(final String className) { - try { - loadClass(className); - return true; - } catch (final ClassNotFoundException e) { - return false; - } - } - - /** - * Returns a class loader or null since some Java implementation is null for the bootstrap class loader. - * - * @return A class loader or null since some Java implementation is null for the bootstrap class loader. - */ - private ClassLoader findClassLoader() { - if (classLoader != null) { - return classLoader; - } - final ClassLoader cl = Thread.currentThread().getContextClassLoader(); - if (cl != null) { - return cl; - } - return getValidClassLoader(getClass()); - } - - /** - * Extracts the required classes from a provider definition. - */ - private String[] getRequiredClasses(final Element providerDef) { - final ArrayList classes = new ArrayList<>(); - final NodeList deps = providerDef.getElementsByTagName("if-available"); - final int count = deps.getLength(); - for (int i = 0; i < count; i++) { - final Element dep = (Element) deps.item(i); - final String className = dep.getAttribute("class-name"); - if (!StringUtils.isEmpty(className)) { - classes.add(className); - } - } - return classes.toArray(ArrayUtils.EMPTY_STRING_ARRAY); - } - - /** - * Extracts the required schemes from a provider definition. - */ - private String[] getRequiredSchemes(final Element providerDef) { - final ArrayList schemes = new ArrayList<>(); - final NodeList deps = providerDef.getElementsByTagName("if-available"); - final int count = deps.getLength(); - for (int i = 0; i < count; i++) { - final Element dep = (Element) deps.item(i); - final String scheme = dep.getAttribute("scheme"); - if (!StringUtils.isEmpty(scheme)) { - schemes.add(scheme); - } - } - return schemes.toArray(ArrayUtils.EMPTY_STRING_ARRAY); - } - - /** - * Extracts the schema names from a provider definition. - */ - private String[] getSchemas(final Element provider) { - final ArrayList schemas = new ArrayList<>(); - final NodeList schemaElements = provider.getElementsByTagName("scheme"); - final int count = schemaElements.getLength(); - for (int i = 0; i < count; i++) { - final Element scheme = (Element) schemaElements.item(i); - schemas.add(scheme.getAttribute("name")); - } - return schemas.toArray(ArrayUtils.EMPTY_STRING_ARRAY); - } - - private ClassLoader getValidClassLoader(final Class clazz) { - return validateClassLoader(clazz.getClassLoader(), clazz); - } - - /** - * Initializes this manager. Adds the providers and replicator. - * - * @throws FileSystemException if an error occurs. - */ - @Override - public void init() throws FileSystemException { - // Set the replicator and temporary file store (use the same component) - final DefaultFileReplicator replicator = createDefaultFileReplicator(); - setReplicator(new PrivilegedFileReplicator(replicator)); - setTemporaryFileStore(replicator); - - if (configUri == null) { - // Use default config - final URL url = getClass().getResource(CONFIG_RESOURCE); - FileSystemException.requireNonNull(url, "vfs.impl/find-config-file.error", CONFIG_RESOURCE); - configUri = url; - } - - configure(configUri); - configurePlugins(); - - // Initialize super-class - super.init(); - } - - /** - * Load a class from different class loaders. - * - * @throws ClassNotFoundException if last {@code loadClass} failed. - * @see #findClassLoader() - */ - private Class loadClass(final String className) throws ClassNotFoundException { - try { - return findClassLoader().loadClass(className); - } catch (final ClassNotFoundException e) { - return getValidClassLoader(getClass()).loadClass(className); - } - } - - /** - * Sets the ClassLoader to use to load the providers. Default is to use the ClassLoader that loaded this class. - * - * @param classLoader The ClassLoader. - */ - public void setClassLoader(final ClassLoader classLoader) { - this.classLoader = classLoader; - } - - /** - * Sets the configuration file for this manager. - * - * @param configUri The URI for this manager. - */ - public void setConfiguration(final String configUri) { - try { - setConfiguration(new URL(configUri)); - } catch (final MalformedURLException e) { - getLogger().warn(e.getLocalizedMessage(), e); - } - } - - /** - * Sets the configuration file for this manager. - * - * @param configUri The URI for this manager. - */ - public void setConfiguration(final URL configUri) { - this.configUri = configUri; - } - - private ClassLoader validateClassLoader(final ClassLoader clazzLoader, final Class clazz) { - return Objects.requireNonNull(clazzLoader, "The class loader for " + clazz - + " is null; some Java implementations use null for the bootstrap class loader."); - } - -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.vfs2.impl; + +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.Objects; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.vfs2.FileSystemException; +import org.apache.commons.vfs2.VfsLog; +import org.apache.commons.vfs2.operations.FileOperationProvider; +import org.apache.commons.vfs2.provider.FileProvider; +import org.apache.commons.vfs2.util.Messages; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +/** + * A {@link org.apache.commons.vfs2.FileSystemManager} that configures itself from an XML (Default: providers.xml) + * configuration file. + *

+ * Certain providers are only loaded and available if the dependent library is in your classpath. You have to configure + * your debugging facility to log "debug" messages to see if a provider was skipped due to "unresolved externals". + *

+ */ +public class StandardFileSystemManager extends DefaultFileSystemManager { + private static final String CONFIG_RESOURCE = "providers.xml"; + private static final String PLUGIN_CONFIG_RESOURCE = "META-INF/vfs-providers.xml"; + + private URL configUri; + private ClassLoader classLoader; + + /** + * Constructs a new instance. + */ + public StandardFileSystemManager() { + // empty + } + + /** + * Adds an extension map. + * + * @param map containing the Elements. + */ + private void addExtensionMap(final Element map) { + final String extension = map.getAttribute("extension"); + final String scheme = map.getAttribute("scheme"); + if (!StringUtils.isEmpty(scheme)) { + addExtensionMap(extension, scheme); + } + } + + /** + * Adds a mime-type map. + * + * @param map containing the Elements. + */ + private void addMimeTypeMap(final Element map) { + final String mimeType = map.getAttribute("mime-type"); + final String scheme = map.getAttribute("scheme"); + addMimeTypeMap(mimeType, scheme); + } + + /** + * Adds a operationProvider from a operationProvider definition. + */ + private void addOperationProvider(final Element providerDef) throws FileSystemException { + final String className = providerDef.getAttribute("class-name"); + + // Attach only to available schemas + final String[] schemas = getSchemas(providerDef); + for (final String schema : schemas) { + if (hasProvider(schema)) { + final FileOperationProvider operationProvider = (FileOperationProvider) createInstance(className); + addOperationProvider(schema, operationProvider); + } + } + } + + /** + * Adds a provider from a provider definition. + * + * @param providerDef the provider definition + * @param isDefault true if the default should be used. + * @throws FileSystemException if an error occurs. + */ + private void addProvider(final Element providerDef, final boolean isDefault) throws FileSystemException { + final String className = providerDef.getAttribute("class-name"); + + // Make sure all required schemes are available + final String[] requiredSchemes = getRequiredSchemes(providerDef); + for (final String requiredScheme : requiredSchemes) { + if (!hasProvider(requiredScheme)) { + final String msg = Messages.getString("vfs.impl/skipping-provider-scheme.debug", className, + requiredScheme); + VfsLog.debug(getLogger(), getLogger(), msg); + return; + } + } + + // Make sure all required classes are in classpath + final String[] requiredClasses = getRequiredClasses(providerDef); + for (final String requiredClass : requiredClasses) { + if (!findClass(requiredClass)) { + final String msg = Messages.getString("vfs.impl/skipping-provider.debug", className, requiredClass); + VfsLog.debug(getLogger(), getLogger(), msg); + return; + } + } + + // Create and register the provider + final FileProvider provider = (FileProvider) createInstance(className); + final String[] schemas = getSchemas(providerDef); + if (schemas.length > 0) { + addProvider(schemas, provider); + } + + // Set as default, if required + if (isDefault) { + setDefaultProvider(provider); + } + } + + /** + * Configures this manager from a parsed XML configuration file + * + * @param config The configuration Element. + * @throws FileSystemException if an error occurs. + */ + private void configure(final Element config) throws FileSystemException { + // Add the providers + final NodeList providers = config.getElementsByTagName("provider"); + final int count = providers.getLength(); + for (int i = 0; i < count; i++) { + final Element provider = (Element) providers.item(i); + addProvider(provider, false); + } + + // Add the operation providers + final NodeList operationProviders = config.getElementsByTagName("operationProvider"); + for (int i = 0; i < operationProviders.getLength(); i++) { + final Element operationProvider = (Element) operationProviders.item(i); + addOperationProvider(operationProvider); + } + + // Add the default provider + final NodeList defProviders = config.getElementsByTagName("default-provider"); + if (defProviders.getLength() > 0) { + final Element provider = (Element) defProviders.item(0); + addProvider(provider, true); + } + + // Add the mime-type maps + final NodeList mimeTypes = config.getElementsByTagName("mime-type-map"); + for (int i = 0; i < mimeTypes.getLength(); i++) { + final Element map = (Element) mimeTypes.item(i); + addMimeTypeMap(map); + } + + // Add the extension maps + final NodeList extensions = config.getElementsByTagName("extension-map"); + for (int i = 0; i < extensions.getLength(); i++) { + final Element map = (Element) extensions.item(i); + addExtensionMap(map); + } + } + + /** + * Configures this manager from an XML configuration file. + * + * @param configUri The URI of the configuration. + * @throws FileSystemException if an error occurs. + */ + private void configure(final URL configUri) throws FileSystemException { + InputStream configStream = null; + try { + // Load up the config + // TODO - validate + final DocumentBuilder builder = createDocumentBuilder(); + configStream = configUri.openStream(); + final Element config = builder.parse(configStream).getDocumentElement(); + + configure(config); + } catch (final Exception e) { + throw new FileSystemException("vfs.impl/load-config.error", configUri.toString(), e); + } finally { + if (configStream != null) { + try { + configStream.close(); + } catch (final IOException e) { + getLogger().warn(e.getLocalizedMessage(), e); + } + } + } + } + + /** + * Scans the classpath to find any dropped plugin. + *

+ * The plugin-description has to be in {@code /META-INF/vfs-providers.xml}. + *

+ * + * @throws FileSystemException if an error occurs. + */ + protected void configurePlugins() throws FileSystemException { + final Enumeration enumResources; + try { + enumResources = enumerateResources(PLUGIN_CONFIG_RESOURCE); + } catch (final IOException e) { + throw new FileSystemException(e); + } + + while (enumResources.hasMoreElements()) { + configure(enumResources.nextElement()); + } + } + + /** + * Gets a new DefaultFileReplicator. + * + * @return a new DefaultFileReplicator. + */ + protected DefaultFileReplicator createDefaultFileReplicator() { + return new DefaultFileReplicator(); + } + + /** + * Configure and create a DocumentBuilder + * + * @return A DocumentBuilder for the configuration. + * @throws ParserConfigurationException if an error occurs. + */ + private DocumentBuilder createDocumentBuilder() throws ParserConfigurationException { + final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setIgnoringElementContentWhitespace(true); + factory.setIgnoringComments(true); + factory.setExpandEntityReferences(true); + return factory.newDocumentBuilder(); + } + + /** + * Creates a provider. + */ + private Object createInstance(final String className) throws FileSystemException { + try { + return loadClass(className).getConstructor().newInstance(); + } catch (final Exception e) { + throw new FileSystemException("vfs.impl/create-provider.error", className, e); + } + } + + /** + * Enumerates resources from different class loaders. + * + * @throws IOException if {@code getResource} failed. + * @see #findClassLoader() + */ + private Enumeration enumerateResources(final String name) throws IOException { + Enumeration enumeration = findClassLoader().getResources(name); + if (enumeration == null || !enumeration.hasMoreElements()) { + enumeration = getValidClassLoader(getClass()).getResources(name); + } + return enumeration; + } + + /** + * Tests if a class is available. + */ + private boolean findClass(final String className) { + try { + loadClass(className); + return true; + } catch (final ClassNotFoundException e) { + return false; + } + } + + /** + * Returns a class loader or null since some Java implementation is null for the bootstrap class loader. + * + * @return A class loader or null since some Java implementation is null for the bootstrap class loader. + */ + private ClassLoader findClassLoader() { + if (classLoader != null) { + return classLoader; + } + final ClassLoader cl = Thread.currentThread().getContextClassLoader(); + if (cl != null) { + return cl; + } + return getValidClassLoader(getClass()); + } + + /** + * Extracts the required classes from a provider definition. + */ + private String[] getRequiredClasses(final Element providerDef) { + final ArrayList classes = new ArrayList<>(); + final NodeList deps = providerDef.getElementsByTagName("if-available"); + final int count = deps.getLength(); + for (int i = 0; i < count; i++) { + final Element dep = (Element) deps.item(i); + final String className = dep.getAttribute("class-name"); + if (!StringUtils.isEmpty(className)) { + classes.add(className); + } + } + return classes.toArray(ArrayUtils.EMPTY_STRING_ARRAY); + } + + /** + * Extracts the required schemes from a provider definition. + */ + private String[] getRequiredSchemes(final Element providerDef) { + final ArrayList schemes = new ArrayList<>(); + final NodeList deps = providerDef.getElementsByTagName("if-available"); + final int count = deps.getLength(); + for (int i = 0; i < count; i++) { + final Element dep = (Element) deps.item(i); + final String scheme = dep.getAttribute("scheme"); + if (!StringUtils.isEmpty(scheme)) { + schemes.add(scheme); + } + } + return schemes.toArray(ArrayUtils.EMPTY_STRING_ARRAY); + } + + /** + * Extracts the schema names from a provider definition. + */ + private String[] getSchemas(final Element provider) { + final ArrayList schemas = new ArrayList<>(); + final NodeList schemaElements = provider.getElementsByTagName("scheme"); + final int count = schemaElements.getLength(); + for (int i = 0; i < count; i++) { + final Element scheme = (Element) schemaElements.item(i); + schemas.add(scheme.getAttribute("name")); + } + return schemas.toArray(ArrayUtils.EMPTY_STRING_ARRAY); + } + + private ClassLoader getValidClassLoader(final Class clazz) { + return validateClassLoader(clazz.getClassLoader(), clazz); + } + + /** + * Initializes this manager. Adds the providers and replicator. + * + * @throws FileSystemException if an error occurs. + */ + @Override + public void init() throws FileSystemException { + // Set the replicator and temporary file store (use the same component) + final DefaultFileReplicator replicator = createDefaultFileReplicator(); + setReplicator(new PrivilegedFileReplicator(replicator)); + setTemporaryFileStore(replicator); + + if (configUri == null) { + // Use default config + final URL url = getClass().getResource(CONFIG_RESOURCE); + FileSystemException.requireNonNull(url, "vfs.impl/find-config-file.error", CONFIG_RESOURCE); + configUri = url; + } + + configure(configUri); + configurePlugins(); + + // Initialize super-class + super.init(); + } + + /** + * Load a class from different class loaders. + * + * @throws ClassNotFoundException if last {@code loadClass} failed. + * @see #findClassLoader() + */ + private Class loadClass(final String className) throws ClassNotFoundException { + try { + return findClassLoader().loadClass(className); + } catch (final ClassNotFoundException e) { + return getValidClassLoader(getClass()).loadClass(className); + } + } + + /** + * Sets the ClassLoader to use to load the providers. Default is to use the ClassLoader that loaded this class. + * + * @param classLoader The ClassLoader. + */ + public void setClassLoader(final ClassLoader classLoader) { + this.classLoader = classLoader; + } + + /** + * Sets the configuration file for this manager. + * + * @param configUri The URI for this manager. + */ + public void setConfiguration(final String configUri) { + try { + setConfiguration(new URL(configUri)); + } catch (final MalformedURLException e) { + getLogger().warn(e.getLocalizedMessage(), e); + } + } + + /** + * Sets the configuration file for this manager. + * + * @param configUri The URI for this manager. + */ + public void setConfiguration(final URL configUri) { + this.configUri = configUri; + } + + private ClassLoader validateClassLoader(final ClassLoader clazzLoader, final Class clazz) { + return Objects.requireNonNull(clazzLoader, "The class loader for " + clazz + + " is null; some Java implementations use null for the bootstrap class loader."); + } + +} diff --git a/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/AbstractFileName.java b/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/AbstractFileName.java index 52e8a5c439..c5b88a5f9b 100644 --- a/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/AbstractFileName.java +++ b/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/AbstractFileName.java @@ -1,542 +1,542 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.vfs2.provider; - -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.vfs2.FileName; -import org.apache.commons.vfs2.FileSystemException; -import org.apache.commons.vfs2.FileType; -import org.apache.commons.vfs2.NameScope; -import org.apache.commons.vfs2.VFS; - -/** - * A default file name implementation. - */ -public abstract class AbstractFileName implements FileName { - - // URI Characters that are possible in local file names, but must be escaped - // for proper URI handling. - // - // How reserved URI chars were selected: - // - // URIs can contain :, /, ?, #, @ - // See https://docs.oracle.com/javase/8/docs/api/java/net/URI.html - // https://datatracker.ietf.org/doc/html/rfc3986#section-2.2 - // - // Since : and / occur before the path, only chars after path are escaped (i.e., # and ?) - // ? is a reserved filesystem character for Windows and Unix, so can't be part of a file name. - // Therefore only # is a reserved char in a URI as part of the path that can be in the file name. - private static final char[] RESERVED_URI_CHARS = {'#', ' '}; - - /** - * Checks whether a path fits in a particular scope of another path. - * - * @param basePath An absolute, normalised path. - * @param path An absolute, normalised path. - * @param scope The NameScope. - * @return true if the path fits in the scope, false otherwise. - */ - public static boolean checkName(final String basePath, final String path, final NameScope scope) { - if (scope == NameScope.FILE_SYSTEM) { - // All good - return true; - } - if (!path.startsWith(basePath)) { - return false; - } - int baseLen = basePath.length(); - if (VFS.isUriStyle()) { - // strip the trailing "/" - baseLen--; - } - if (scope != null) { - switch (scope) { - case CHILD: - return path.length() != baseLen && (baseLen <= 1 || path.charAt(baseLen) == SEPARATOR_CHAR) && path.indexOf(SEPARATOR_CHAR, baseLen + 1) == -1; - case DESCENDENT: - return path.length() != baseLen && (baseLen <= 1 || path.charAt(baseLen) == SEPARATOR_CHAR); - case DESCENDENT_OR_SELF: - return baseLen <= 1 || path.length() <= baseLen || path.charAt(baseLen) == SEPARATOR_CHAR; - default: - break; - } - } - throw new IllegalArgumentException(); - } - private final String scheme; - private final String absolutePath; - - private FileType type; - // Cached attributes - private String uriString; - private String baseName; - private String rootUri; - private String extension; - - private String decodedAbsPath; - - private String key; - - /** - * Constructs a new instance for subclasses. - * - * @param scheme The scheme. - * @param absolutePath the absolute path, maybe empty or null. - * @param type the file type. - */ - public AbstractFileName(final String scheme, final String absolutePath, final FileType type) { - rootUri = null; - this.scheme = scheme; - this.type = type; - if (StringUtils.isEmpty(absolutePath)) { - this.absolutePath = ROOT_PATH; - } else if (absolutePath.length() > 1 && absolutePath.endsWith("/")) { - this.absolutePath = absolutePath.substring(0, absolutePath.length() - 1); - } else { - this.absolutePath = absolutePath; - } - } - - /** - * Builds the root URI for this file name. Note that the root URI must not end with a separator character. - * - * @param buffer A StringBuilder to use to construct the URI. - * @param addPassword true if the password should be added, false otherwise. - */ - protected abstract void appendRootUri(StringBuilder buffer, boolean addPassword); - - /** - * Implement Comparable. - * - * @param obj another abstract file name - * @return negative number if less than, 0 if equal, positive if greater than. - */ - @Override - public int compareTo(final FileName obj) { - final AbstractFileName name = (AbstractFileName) obj; - return getKey().compareTo(name.getKey()); - } - - /** - * Factory method for creating name instances. - * - * @param absolutePath The absolute path. - * @param fileType The FileType. - * @return The FileName. - */ - public abstract FileName createName(String absolutePath, FileType fileType); - - /** - * Creates a URI. - * - * @return a URI. - */ - protected String createURI() { - return createURI(false, true); - } - - private String createURI(final boolean useAbsolutePath, final boolean usePassword) { - final StringBuilder buffer = new StringBuilder(); - appendRootUri(buffer, usePassword); - buffer.append(handleURISpecialCharacters(useAbsolutePath ? absolutePath : getPath())); - return buffer.toString(); - } - - @Override - public boolean equals(final Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - final AbstractFileName that = (AbstractFileName) o; - - return getKey().equals(that.getKey()); - } - - /** - * Returns the base name of the file. - * - * @return The base name of the file. - */ - @Override - public String getBaseName() { - if (baseName == null) { - final int idx = getPath().lastIndexOf(SEPARATOR_CHAR); - if (idx == -1) { - baseName = getPath(); - } else { - baseName = getPath().substring(idx + 1); - } - } - - return baseName; - } - - /** - * Returns the depth of this file name, within its file system. - * - * @return The depth of the file name. - */ - @Override - public int getDepth() { - final int len = getPath().length(); - if (len == 0 || len == 1 && getPath().charAt(0) == SEPARATOR_CHAR) { - return 0; - } - int depth = 1; - for (int pos = 0; pos > -1 && pos < len; depth++) { - pos = getPath().indexOf(SEPARATOR_CHAR, pos + 1); - } - return depth; - } - - /** - * Returns the extension of this file name. - * - * @return The file extension. - */ - @Override - public String getExtension() { - if (extension == null) { - getBaseName(); - final int pos = baseName.lastIndexOf('.'); - // if ((pos == -1) || (pos == baseName.length() - 1)) - // imario@ops.co.at: Review of patch from adagoubard@chello.nl - // do not treat file names like - // .bashrc c:\windows\.java c:\windows\.javaws c:\windows\.jedit c:\windows\.appletviewer - // as extension - if (pos < 1 || pos == baseName.length() - 1) { - // No extension - extension = ""; - } else { - extension = baseName.substring(pos + 1).intern(); - } - } - return extension; - } - - /** - * Returns the URI without a password. - * - * @return Returns the URI without a password. - */ - @Override - public String getFriendlyURI() { - return createURI(false, false); - } - - /** - * Create a path that does not use the FileType since that field is not immutable. - * - * @return The key. - */ - private String getKey() { - if (key == null) { - key = getURI(); - } - return key; - } - - /** - * Returns the name of the parent of the file. - * - * @return the FileName of the parent. - */ - @Override - public FileName getParent() { - final String parentPath; - final int idx = getPath().lastIndexOf(SEPARATOR_CHAR); - if (idx == -1 || idx == getPath().length() - 1) { - // No parent - return null; - } - if (idx == 0) { - // Root is the parent - parentPath = SEPARATOR; - } else { - parentPath = getPath().substring(0, idx); - } - return createName(parentPath, FileType.FOLDER); - } - - /** - * Returns the absolute path of the file, relative to the root of the file system that the file belongs to. - * - * @return The path String. - */ - @Override - public String getPath() { - if (VFS.isUriStyle()) { - return absolutePath + getUriTrailer(); - } - return absolutePath; - } - - /** - * Returns the decoded path. - * - * @return The decoded path String. - * @throws FileSystemException If an error occurs. - */ - @Override - public String getPathDecoded() throws FileSystemException { - if (decodedAbsPath == null) { - decodedAbsPath = UriParser.decode(getPath()); - } - - return decodedAbsPath; - } - - /** - * Converts a file name to a relative name, relative to this file name. - * - * @param name The FileName. - * @return The relative path to the file. - * @throws FileSystemException if an error occurs. - */ - @Override - public String getRelativeName(final FileName name) throws FileSystemException { - final String path = name.getPath(); - - // Calculate the common prefix - final int basePathLen = getPath().length(); - final int pathLen = path.length(); - - // Deal with root - if (basePathLen == 1 && pathLen == 1) { - return "."; - } - if (basePathLen == 1) { - return path.substring(1); - } - - final int maxlen = Math.min(basePathLen, pathLen); - int pos = 0; - while (pos < maxlen && getPath().charAt(pos) == path.charAt(pos)) { - pos++; - } - - if (pos == basePathLen && pos == pathLen) { - // Same names - return "."; - } - if (pos == basePathLen && pos < pathLen && path.charAt(pos) == SEPARATOR_CHAR) { - // A descendent of the base path - return path.substring(pos + 1); - } - - // Strip the common prefix off the path - final StringBuilder buffer = new StringBuilder(); - if (pathLen > 1 && (pos < pathLen || getPath().charAt(pos) != SEPARATOR_CHAR)) { - // Not a direct ancestor, need to back up - pos = getPath().lastIndexOf(SEPARATOR_CHAR, pos); - buffer.append(path.substring(pos)); - } - - // Prepend a '../' for each element in the base path past the common - // prefix - buffer.insert(0, ".."); - pos = getPath().indexOf(SEPARATOR_CHAR, pos + 1); - while (pos != -1) { - buffer.insert(0, "../"); - pos = getPath().indexOf(SEPARATOR_CHAR, pos + 1); - } - - return buffer.toString(); - } - - /** - * find the root of the file system. - * - * @return The root FileName. - */ - @Override - public FileName getRoot() { - FileName root = this; - while (root.getParent() != null) { - root = root.getParent(); - } - - return root; - } - - /** - * Returns the root URI of the file system this file belongs to. - * - * @return The URI of the root. - */ - @Override - public String getRootURI() { - if (rootUri == null) { - final StringBuilder buffer = new StringBuilder(); - appendRootUri(buffer, true); - buffer.append(SEPARATOR_CHAR); - rootUri = buffer.toString().intern(); - } - return rootUri; - } - - /** - * Returns the URI scheme of this file. - * - * @return The protocol used to access the file. - */ - @Override - public String getScheme() { - return scheme; - } - - /** - * Returns the requested or current type of this name. - *

- * The "requested" type is the one determined during resolving the name. n this case the name is a - * {@link FileType#FOLDER} if it ends with an "/" else it will be a {@link FileType#FILE}. - *

- *

- * Once attached it will be changed to reflect the real type of this resource. - *

- * - * @return {@link FileType#FOLDER} or {@link FileType#FILE} - */ - @Override - public FileType getType() { - return type; - } - - /** - * Returns the absolute URI of the file. - * - * @return The absolute URI of the file. - */ - @Override - public String getURI() { - if (uriString == null) { - uriString = createURI(); - } - return uriString; - } - - /** - * Gets the string to end a URI. - * - * @return the string to end a URI - */ - protected String getUriTrailer() { - return getType().hasChildren() ? "/" : ""; - } - - private String handleURISpecialCharacters(String uri) { - if (!StringUtils.isEmpty(uri)) { - try { - // VFS-325: Handle URI special characters in file name - // Decode the base URI and re-encode with URI special characters - uri = UriParser.decode(uri); - - return UriParser.encode(uri, RESERVED_URI_CHARS); - } catch (final FileSystemException ignore) { // NOPMD - // Default to base URI value? - } - } - - return uri; - } - - @Override - public int hashCode() { - return getKey().hashCode(); - } - - /** - * Determines if another file name is an ancestor of this file name. - * - * @param ancestor The FileName to check. - * @return true if the FileName is an ancestor, false otherwise. - */ - @Override - public boolean isAncestor(final FileName ancestor) { - if (!ancestor.getRootURI().equals(getRootURI())) { - return false; - } - return checkName(ancestor.getPath(), getPath(), NameScope.DESCENDENT); - } - - /** - * Determines if another file name is a descendent of this file name. - * - * @param descendent The FileName to check. - * @return true if the FileName is a descendent, false otherwise. - */ - @Override - public boolean isDescendent(final FileName descendent) { - return isDescendent(descendent, NameScope.DESCENDENT); - } - - /** - * Determines if another file name is a descendent of this file name. - * - * @param descendent The FileName to check. - * @param scope The NameScope. - * @return true if the FileName is a descendent, false otherwise. - */ - @Override - public boolean isDescendent(final FileName descendent, final NameScope scope) { - if (!descendent.getRootURI().equals(getRootURI())) { - return false; - } - return checkName(getPath(), descendent.getPath(), scope); - } - - /** - * Checks if this file name is a name for a regular file by using its type. - * - * @return true if this file is a regular file. - * @throws FileSystemException may be thrown by subclasses. - * @see #getType() - * @see FileType#FILE - */ - @Override - public boolean isFile() throws FileSystemException { - // Use equals instead of == to avoid any class loader worries. - return FileType.FILE.equals(getType()); - } - - /** - * Sets the type of this file e.g. when it will be attached. - * - * @param type {@link FileType#FOLDER} or {@link FileType#FILE} - * @throws FileSystemException if an error occurs. - */ - void setType(final FileType type) throws FileSystemException { - if (type != FileType.FOLDER && type != FileType.FILE && type != FileType.FILE_OR_FOLDER) { - throw new FileSystemException("vfs.provider/filename-type.error"); - } - this.type = type; - } - - /** - * Returns the URI of the file. - * - * @return the FileName as a URI. - */ - @Override - public String toString() { - return getURI(); - } -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.vfs2.provider; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.vfs2.FileName; +import org.apache.commons.vfs2.FileSystemException; +import org.apache.commons.vfs2.FileType; +import org.apache.commons.vfs2.NameScope; +import org.apache.commons.vfs2.VFS; + +/** + * A default file name implementation. + */ +public abstract class AbstractFileName implements FileName { + + // URI Characters that are possible in local file names, but must be escaped + // for proper URI handling. + // + // How reserved URI chars were selected: + // + // URIs can contain :, /, ?, #, @ + // See https://docs.oracle.com/javase/8/docs/api/java/net/URI.html + // https://datatracker.ietf.org/doc/html/rfc3986#section-2.2 + // + // Since : and / occur before the path, only chars after path are escaped (i.e., # and ?) + // ? is a reserved filesystem character for Windows and Unix, so can't be part of a file name. + // Therefore only # is a reserved char in a URI as part of the path that can be in the file name. + private static final char[] RESERVED_URI_CHARS = {'#', ' '}; + + /** + * Checks whether a path fits in a particular scope of another path. + * + * @param basePath An absolute, normalised path. + * @param path An absolute, normalised path. + * @param scope The NameScope. + * @return true if the path fits in the scope, false otherwise. + */ + public static boolean checkName(final String basePath, final String path, final NameScope scope) { + if (scope == NameScope.FILE_SYSTEM) { + // All good + return true; + } + if (!path.startsWith(basePath)) { + return false; + } + int baseLen = basePath.length(); + if (VFS.isUriStyle()) { + // strip the trailing "/" + baseLen--; + } + if (scope != null) { + switch (scope) { + case CHILD: + return path.length() != baseLen && (baseLen <= 1 || path.charAt(baseLen) == SEPARATOR_CHAR) && path.indexOf(SEPARATOR_CHAR, baseLen + 1) == -1; + case DESCENDENT: + return path.length() != baseLen && (baseLen <= 1 || path.charAt(baseLen) == SEPARATOR_CHAR); + case DESCENDENT_OR_SELF: + return baseLen <= 1 || path.length() <= baseLen || path.charAt(baseLen) == SEPARATOR_CHAR; + default: + break; + } + } + throw new IllegalArgumentException(); + } + private final String scheme; + private final String absolutePath; + + private FileType type; + // Cached attributes + private String uriString; + private String baseName; + private String rootUri; + private String extension; + + private String decodedAbsPath; + + private String key; + + /** + * Constructs a new instance for subclasses. + * + * @param scheme The scheme. + * @param absolutePath the absolute path, maybe empty or null. + * @param type the file type. + */ + public AbstractFileName(final String scheme, final String absolutePath, final FileType type) { + rootUri = null; + this.scheme = scheme; + this.type = type; + if (StringUtils.isEmpty(absolutePath)) { + this.absolutePath = ROOT_PATH; + } else if (absolutePath.length() > 1 && absolutePath.endsWith("/")) { + this.absolutePath = absolutePath.substring(0, absolutePath.length() - 1); + } else { + this.absolutePath = absolutePath; + } + } + + /** + * Builds the root URI for this file name. Note that the root URI must not end with a separator character. + * + * @param buffer A StringBuilder to use to construct the URI. + * @param addPassword true if the password should be added, false otherwise. + */ + protected abstract void appendRootUri(StringBuilder buffer, boolean addPassword); + + /** + * Implement Comparable. + * + * @param obj another abstract file name + * @return negative number if less than, 0 if equal, positive if greater than. + */ + @Override + public int compareTo(final FileName obj) { + final AbstractFileName name = (AbstractFileName) obj; + return getKey().compareTo(name.getKey()); + } + + /** + * Factory method for creating name instances. + * + * @param absolutePath The absolute path. + * @param fileType The FileType. + * @return The FileName. + */ + public abstract FileName createName(String absolutePath, FileType fileType); + + /** + * Creates a URI. + * + * @return a URI. + */ + protected String createURI() { + return createURI(false, true); + } + + private String createURI(final boolean useAbsolutePath, final boolean usePassword) { + final StringBuilder buffer = new StringBuilder(); + appendRootUri(buffer, usePassword); + buffer.append(handleURISpecialCharacters(useAbsolutePath ? absolutePath : getPath())); + return buffer.toString(); + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + final AbstractFileName that = (AbstractFileName) o; + + return getKey().equals(that.getKey()); + } + + /** + * Returns the base name of the file. + * + * @return The base name of the file. + */ + @Override + public String getBaseName() { + if (baseName == null) { + final int idx = getPath().lastIndexOf(SEPARATOR_CHAR); + if (idx == -1) { + baseName = getPath(); + } else { + baseName = getPath().substring(idx + 1); + } + } + + return baseName; + } + + /** + * Returns the depth of this file name, within its file system. + * + * @return The depth of the file name. + */ + @Override + public int getDepth() { + final int len = getPath().length(); + if (len == 0 || len == 1 && getPath().charAt(0) == SEPARATOR_CHAR) { + return 0; + } + int depth = 1; + for (int pos = 0; pos > -1 && pos < len; depth++) { + pos = getPath().indexOf(SEPARATOR_CHAR, pos + 1); + } + return depth; + } + + /** + * Returns the extension of this file name. + * + * @return The file extension. + */ + @Override + public String getExtension() { + if (extension == null) { + getBaseName(); + final int pos = baseName.lastIndexOf('.'); + // if ((pos == -1) || (pos == baseName.length() - 1)) + // imario@ops.co.at: Review of patch from adagoubard@chello.nl + // do not treat file names like + // .bashrc c:\windows\.java c:\windows\.javaws c:\windows\.jedit c:\windows\.appletviewer + // as extension + if (pos < 1 || pos == baseName.length() - 1) { + // No extension + extension = ""; + } else { + extension = baseName.substring(pos + 1).intern(); + } + } + return extension; + } + + /** + * Returns the URI without a password. + * + * @return Returns the URI without a password. + */ + @Override + public String getFriendlyURI() { + return createURI(false, false); + } + + /** + * Create a path that does not use the FileType since that field is not immutable. + * + * @return The key. + */ + private String getKey() { + if (key == null) { + key = getURI(); + } + return key; + } + + /** + * Returns the name of the parent of the file. + * + * @return the FileName of the parent. + */ + @Override + public FileName getParent() { + final String parentPath; + final int idx = getPath().lastIndexOf(SEPARATOR_CHAR); + if (idx == -1 || idx == getPath().length() - 1) { + // No parent + return null; + } + if (idx == 0) { + // Root is the parent + parentPath = SEPARATOR; + } else { + parentPath = getPath().substring(0, idx); + } + return createName(parentPath, FileType.FOLDER); + } + + /** + * Returns the absolute path of the file, relative to the root of the file system that the file belongs to. + * + * @return The path String. + */ + @Override + public String getPath() { + if (VFS.isUriStyle()) { + return absolutePath + getUriTrailer(); + } + return absolutePath; + } + + /** + * Returns the decoded path. + * + * @return The decoded path String. + * @throws FileSystemException If an error occurs. + */ + @Override + public String getPathDecoded() throws FileSystemException { + if (decodedAbsPath == null) { + decodedAbsPath = UriParser.decode(getPath()); + } + + return decodedAbsPath; + } + + /** + * Converts a file name to a relative name, relative to this file name. + * + * @param name The FileName. + * @return The relative path to the file. + * @throws FileSystemException if an error occurs. + */ + @Override + public String getRelativeName(final FileName name) throws FileSystemException { + final String path = name.getPath(); + + // Calculate the common prefix + final int basePathLen = getPath().length(); + final int pathLen = path.length(); + + // Deal with root + if (basePathLen == 1 && pathLen == 1) { + return "."; + } + if (basePathLen == 1) { + return path.substring(1); + } + + final int maxlen = Math.min(basePathLen, pathLen); + int pos = 0; + while (pos < maxlen && getPath().charAt(pos) == path.charAt(pos)) { + pos++; + } + + if (pos == basePathLen && pos == pathLen) { + // Same names + return "."; + } + if (pos == basePathLen && pos < pathLen && path.charAt(pos) == SEPARATOR_CHAR) { + // A descendent of the base path + return path.substring(pos + 1); + } + + // Strip the common prefix off the path + final StringBuilder buffer = new StringBuilder(); + if (pathLen > 1 && (pos < pathLen || getPath().charAt(pos) != SEPARATOR_CHAR)) { + // Not a direct ancestor, need to back up + pos = getPath().lastIndexOf(SEPARATOR_CHAR, pos); + buffer.append(path.substring(pos)); + } + + // Prepend a '../' for each element in the base path past the common + // prefix + buffer.insert(0, ".."); + pos = getPath().indexOf(SEPARATOR_CHAR, pos + 1); + while (pos != -1) { + buffer.insert(0, "../"); + pos = getPath().indexOf(SEPARATOR_CHAR, pos + 1); + } + + return buffer.toString(); + } + + /** + * find the root of the file system. + * + * @return The root FileName. + */ + @Override + public FileName getRoot() { + FileName root = this; + while (root.getParent() != null) { + root = root.getParent(); + } + + return root; + } + + /** + * Returns the root URI of the file system this file belongs to. + * + * @return The URI of the root. + */ + @Override + public String getRootURI() { + if (rootUri == null) { + final StringBuilder buffer = new StringBuilder(); + appendRootUri(buffer, true); + buffer.append(SEPARATOR_CHAR); + rootUri = buffer.toString().intern(); + } + return rootUri; + } + + /** + * Returns the URI scheme of this file. + * + * @return The protocol used to access the file. + */ + @Override + public String getScheme() { + return scheme; + } + + /** + * Returns the requested or current type of this name. + *

+ * The "requested" type is the one determined during resolving the name. n this case the name is a + * {@link FileType#FOLDER} if it ends with an "/" else it will be a {@link FileType#FILE}. + *

+ *

+ * Once attached it will be changed to reflect the real type of this resource. + *

+ * + * @return {@link FileType#FOLDER} or {@link FileType#FILE} + */ + @Override + public FileType getType() { + return type; + } + + /** + * Returns the absolute URI of the file. + * + * @return The absolute URI of the file. + */ + @Override + public String getURI() { + if (uriString == null) { + uriString = createURI(); + } + return uriString; + } + + /** + * Gets the string to end a URI. + * + * @return the string to end a URI + */ + protected String getUriTrailer() { + return getType().hasChildren() ? "/" : ""; + } + + private String handleURISpecialCharacters(String uri) { + if (!StringUtils.isEmpty(uri)) { + try { + // VFS-325: Handle URI special characters in file name + // Decode the base URI and re-encode with URI special characters + uri = UriParser.decode(uri); + + return UriParser.encode(uri, RESERVED_URI_CHARS); + } catch (final FileSystemException ignore) { // NOPMD + // Default to base URI value? + } + } + + return uri; + } + + @Override + public int hashCode() { + return getKey().hashCode(); + } + + /** + * Determines if another file name is an ancestor of this file name. + * + * @param ancestor The FileName to check. + * @return true if the FileName is an ancestor, false otherwise. + */ + @Override + public boolean isAncestor(final FileName ancestor) { + if (!ancestor.getRootURI().equals(getRootURI())) { + return false; + } + return checkName(ancestor.getPath(), getPath(), NameScope.DESCENDENT); + } + + /** + * Determines if another file name is a descendent of this file name. + * + * @param descendent The FileName to check. + * @return true if the FileName is a descendent, false otherwise. + */ + @Override + public boolean isDescendent(final FileName descendent) { + return isDescendent(descendent, NameScope.DESCENDENT); + } + + /** + * Determines if another file name is a descendent of this file name. + * + * @param descendent The FileName to check. + * @param scope The NameScope. + * @return true if the FileName is a descendent, false otherwise. + */ + @Override + public boolean isDescendent(final FileName descendent, final NameScope scope) { + if (!descendent.getRootURI().equals(getRootURI())) { + return false; + } + return checkName(getPath(), descendent.getPath(), scope); + } + + /** + * Checks if this file name is a name for a regular file by using its type. + * + * @return true if this file is a regular file. + * @throws FileSystemException may be thrown by subclasses. + * @see #getType() + * @see FileType#FILE + */ + @Override + public boolean isFile() throws FileSystemException { + // Use equals instead of == to avoid any class loader worries. + return FileType.FILE.equals(getType()); + } + + /** + * Sets the type of this file e.g. when it will be attached. + * + * @param type {@link FileType#FOLDER} or {@link FileType#FILE} + * @throws FileSystemException if an error occurs. + */ + void setType(final FileType type) throws FileSystemException { + if (type != FileType.FOLDER && type != FileType.FILE && type != FileType.FILE_OR_FOLDER) { + throw new FileSystemException("vfs.provider/filename-type.error"); + } + this.type = type; + } + + /** + * Returns the URI of the file. + * + * @return the FileName as a URI. + */ + @Override + public String toString() { + return getURI(); + } +} diff --git a/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/AbstractFileObject.java b/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/AbstractFileObject.java index 6f65e63f62..eca79fc787 100644 --- a/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/AbstractFileObject.java +++ b/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/AbstractFileObject.java @@ -1,1899 +1,1899 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.vfs2.provider; - -import java.io.BufferedInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.URL; -import java.security.AccessController; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; -import java.security.cert.Certificate; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.stream.Stream; - -import org.apache.commons.io.function.Uncheck; -import org.apache.commons.vfs2.Capability; -import org.apache.commons.vfs2.FileContent; -import org.apache.commons.vfs2.FileContentInfoFactory; -import org.apache.commons.vfs2.FileName; -import org.apache.commons.vfs2.FileNotFolderException; -import org.apache.commons.vfs2.FileObject; -import org.apache.commons.vfs2.FileSelector; -import org.apache.commons.vfs2.FileSystem; -import org.apache.commons.vfs2.FileSystemException; -import org.apache.commons.vfs2.FileType; -import org.apache.commons.vfs2.NameScope; -import org.apache.commons.vfs2.RandomAccessContent; -import org.apache.commons.vfs2.Selectors; -import org.apache.commons.vfs2.operations.DefaultFileOperations; -import org.apache.commons.vfs2.operations.FileOperations; -import org.apache.commons.vfs2.util.FileObjectUtils; -import org.apache.commons.vfs2.util.RandomAccessMode; - -/** - * A partial file object implementation. - * - * TODO - Chop this class up - move all the protected methods to several interfaces, so that structure and content can - * be separately overridden. - * - *

- * TODO - Check caps in methods like getChildren(), etc, and give better error messages (eg 'this file type does not - * support listing children', vs 'this is not a folder') - *

- * - * @param An AbstractFileSystem subclass - */ -public abstract class AbstractFileObject implements FileObject { - - /** - * Same as {@link BufferedInputStream}. - */ - public static final int DEFAULT_BUFFER_SIZE = 8192; - - private static final int INITIAL_LIST_SIZE = 5; - - private static final String DO_GET_INPUT_STREAM_INT = "doGetInputStream(int)"; - - /** - * Traverses a file. - */ - private static void traverse(final DefaultFileSelectorInfo fileInfo, final FileSelector selector, - final boolean depthwise, final List selected) throws Exception { - // Check the file itself - final FileObject file = fileInfo.getFile(); - final int index = selected.size(); - - // If the file is a folder, traverse it - if (file.getType().hasChildren() && selector.traverseDescendants(fileInfo)) { - final int curDepth = fileInfo.getDepth(); - fileInfo.setDepth(curDepth + 1); - - // Traverse the children - final FileObject[] children = file.getChildren(); - for (final FileObject child : children) { - fileInfo.setFile(child); - traverse(fileInfo, selector, depthwise, selected); - } - - fileInfo.setFile(file); - fileInfo.setDepth(curDepth); - } - - // Add the file if doing depthwise traversal - if (selector.includeFile(fileInfo)) { - if (depthwise) { - // Add this file after its descendants - selected.add(file); - } else { - // Add this file before its descendants - selected.add(index, file); - } - } - } - private final AbstractFileName fileName; - - private final AFS fileSystem; - private FileContent content; - // Cached info - private boolean attached; - - private FileType type; - private FileObject parent; - - // Changed to hold only the name of the children and let the object - // go into the global files cache - // private FileObject[] children; - private FileName[] children; - - private List objects; - - /** - * FileServices instance. - */ - private FileOperations operations; - - /** - * Constructs a new instance for subclasses. - * - * @param fileName the file name. - * @param fileSystem the file system. - */ - protected AbstractFileObject(final AbstractFileName fileName, final AFS fileSystem) { - this.fileName = fileName; - this.fileSystem = fileSystem; - fileSystem.fileObjectHanded(this); - } - - /** - * Attaches to the file. - * - * @throws FileSystemException if an error occurs. - */ - private void attach() throws FileSystemException { - synchronized (fileSystem) { - if (attached) { - return; - } - - try { - // Attach and determine the file type - doAttach(); - attached = true; - // now the type could already be injected by doAttach (e.g. from parent to child) - - /* - * VFS-210: determine the type when really asked fore if (type == null) { setFileType(doGetType()); } if - * (type == null) { setFileType(FileType.IMAGINARY); } - */ - } catch (final Exception exc) { - throw new FileSystemException("vfs.provider/get-type.error", exc, fileName); - } - - // fs.fileAttached(this); - } - } - - /** - * Queries the object if a simple rename to the file name of {@code newfile} is possible. - * - * @param newfile the new file name - * @return true if rename is possible - */ - @Override - public boolean canRenameTo(final FileObject newfile) { - return fileSystem == newfile.getFileSystem(); - } - - /** - * Notifies the file that its children have changed. - * - * @param childName The name of the child. - * @param newType The type of the child. - * @throws Exception if an error occurs. - */ - protected void childrenChanged(final FileName childName, final FileType newType) throws Exception { - // TODO - this may be called when not attached - - if (children != null && childName != null && newType != null) { - // TODO - figure out if children[] can be replaced by list - final ArrayList list = new ArrayList<>(Arrays.asList(children)); - if (newType.equals(FileType.IMAGINARY)) { - list.remove(childName); - } else { - list.add(childName); - } - children = list.toArray(FileName.EMPTY_ARRAY); - } - - // removeChildrenCache(); - onChildrenChanged(childName, newType); - } - - /** - * Closes this file, and its content. - * - * @throws FileSystemException if an error occurs. - */ - @Override - public void close() throws FileSystemException { - FileSystemException exc = null; - - synchronized (fileSystem) { - // Close the content - if (content != null) { - try { - content.close(); - content = null; - } catch (final FileSystemException e) { - exc = e; - } - } - - // Detach from the file - try { - detach(); - } catch (final Exception e) { - exc = new FileSystemException("vfs.provider/close.error", fileName, e); - } - - if (exc != null) { - throw exc; - } - } - } - - /** - * Compares two FileObjects (ignores case). - * - * @param file the object to compare. - * @return a negative integer, zero, or a positive integer when this object is less than, equal to, or greater than - * the given object. - */ - @Override - public int compareTo(final FileObject file) { - if (file == null) { - return 1; - } - return this.toString().compareToIgnoreCase(file.toString()); - } - - /** - * Copies another file to this file. - * - * @param file The FileObject to copy. - * @param selector The FileSelector. - * @throws FileSystemException if an error occurs. - */ - @Override - public void copyFrom(final FileObject file, final FileSelector selector) throws FileSystemException { - if (!FileObjectUtils.exists(file)) { - throw new FileSystemException("vfs.provider/copy-missing-file.error", file); - } - - // Locate the files to copy across - final ArrayList files = new ArrayList<>(); - file.findFiles(selector, false, files); - - // Copy everything across - for (final FileObject srcFile : files) { - // Determine the destination file - final String relPath = file.getName().getRelativeName(srcFile.getName()); - final FileObject destFile = resolveFile(relPath, NameScope.DESCENDENT_OR_SELF); - - // Clean up the destination file, if necessary - if (FileObjectUtils.exists(destFile) && destFile.getType() != srcFile.getType()) { - // The destination file exists, and is not of the same type, - // so delete it - // TODO - add a pluggable policy for deleting and overwriting existing files - destFile.deleteAll(); - } - - // Copy across - try { - if (srcFile.getType().hasContent()) { - FileObjectUtils.writeContent(srcFile, destFile); - } else if (srcFile.getType().hasChildren()) { - destFile.createFolder(); - } - } catch (final IOException e) { - throw new FileSystemException("vfs.provider/copy-file.error", e, srcFile, destFile); - } - } - } - - /** - * Creates this file, if it does not exist. - * - * @throws FileSystemException if an error occurs. - */ - @Override - public void createFile() throws FileSystemException { - synchronized (fileSystem) { - try { - // VFS-210: We do not want to trunc any existing file, checking for its existence is - // still required - if (exists() && !isFile()) { - throw new FileSystemException("vfs.provider/create-file.error", fileName); - } - - if (!exists()) { - try (FileContent content = getContent()) { - if (content != null) { - try (OutputStream ignored = content.getOutputStream()) { - // Avoids NPE on OutputStream#close() - } - } - } - } - } catch (final RuntimeException re) { - throw re; - } catch (final Exception e) { - throw new FileSystemException("vfs.provider/create-file.error", fileName, e); - } - } - } - - /** - * Creates this folder, if it does not exist. Also creates any ancestor files which do not exist. - * - * @throws FileSystemException if an error occurs. - */ - @Override - public void createFolder() throws FileSystemException { - synchronized (fileSystem) { - // VFS-210: we create a folder only if it does not already exist. So this check should be safe. - if (getType().hasChildren()) { - // Already exists as correct type - return; - } - if (getType() != FileType.IMAGINARY) { - throw new FileSystemException("vfs.provider/create-folder-mismatched-type.error", fileName); - } - /* - * VFS-210: checking for writable is not always possible as the security constraint might be more complex - * if (!isWriteable()) { throw new FileSystemException("vfs.provider/create-folder-read-only.error", name); - * } - */ - - // Traverse up the hierarchy and make sure everything is a folder - final FileObject parent = getParent(); - if (parent != null) { - parent.createFolder(); - } - - try { - // Create the folder - doCreateFolder(); - - // Update cached info - handleCreate(FileType.FOLDER); - } catch (final RuntimeException re) { - throw re; - } catch (final Exception exc) { - throw new FileSystemException("vfs.provider/create-folder.error", fileName, exc); - } - } - } - - /** - * Deletes this file. - *

- * TODO - This will not fail if this is a non-empty folder. - *

- * - * @return true if this object has been deleted - * @throws FileSystemException if an error occurs. - */ - @Override - public boolean delete() throws FileSystemException { - return delete(Selectors.SELECT_SELF) > 0; - } - - /** - * Deletes this file, and all children matching the {@code selector}. - * - * @param selector The FileSelector. - * @return the number of deleted files. - * @throws FileSystemException if an error occurs. - */ - @Override - public int delete(final FileSelector selector) throws FileSystemException { - int nuofDeleted = 0; - - /* - * VFS-210 if (getType() == FileType.IMAGINARY) { // File does not exist return nuofDeleted; } - */ - - // Locate all the files to delete - final ArrayList files = new ArrayList<>(); - findFiles(selector, true, files); - - // Delete 'em - for (final FileObject fileObject : files) { - final AbstractFileObject file = FileObjectUtils.getAbstractFileObject(fileObject); - // file.attach(); - // VFS-210: It seems impossible to me that findFiles will return a list with hidden files/directories - // in it, else it would not be hidden. Checking for the file-type seems ok in this case - // If the file is a folder, make sure all its children have been deleted - if (file.getType().hasChildren() && file.getChildren().length != 0) { - // Skip - as the selector forced us not to delete all files - continue; - } - // Delete the file - if (file.deleteSelf()) { - nuofDeleted++; - } - } - return nuofDeleted; - } - - /** - * Deletes this file and all children. Shorthand for {@code delete(Selectors.SELECT_ALL)} - * - * @return the number of deleted files. - * @throws FileSystemException if an error occurs. - * @see #delete(FileSelector) - * @see Selectors#SELECT_ALL - */ - @Override - public int deleteAll() throws FileSystemException { - return this.delete(Selectors.SELECT_ALL); - } - - /** - * Deletes this file, once all its children have been deleted - * - * @return true if this file has been deleted - * @throws FileSystemException if an error occurs. - */ - private boolean deleteSelf() throws FileSystemException { - synchronized (fileSystem) { - // It's possible to delete a read-only file if you have write-execute access to the directory - - /* - * VFS-210 if (getType() == FileType.IMAGINARY) { // File does not exist return false; } - */ - - try { - // Delete the file - doDelete(); - - // Update cached info - handleDelete(); - } catch (final RuntimeException re) { - throw re; - } catch (final Exception exc) { - throw new FileSystemException("vfs.provider/delete.error", exc, fileName); - } - - return true; - } - } - - /** - * Detaches this file, invalidating all cached info. This will force a call to {@link #doAttach} next time this file - * is used. - * - * @throws Exception if an error occurs. - */ - private void detach() throws Exception { - synchronized (fileSystem) { - if (attached) { - try { - doDetach(); - } finally { - attached = false; - setFileType(null); - parent = null; - - // fs.fileDetached(this); - - removeChildrenCache(); - // children = null; - } - } - } - } - - /** - * Attaches this file object to its file resource. - *

- * This method is called before any of the doBlah() or onBlah() methods. Sub-classes can use this method to perform - * lazy initialization. - *

- *

- * This implementation does nothing. - *

- * - * @throws Exception if an error occurs. - */ - protected void doAttach() throws Exception { - // noop - } - - /** - * Create a FileContent implementation. - * - * @return The FileContent. - * @throws FileSystemException if an error occurs. - * @since 2.0 - */ - protected FileContent doCreateFileContent() throws FileSystemException { - return new DefaultFileContent(this, getFileContentInfoFactory()); - } - - /** - * Creates this file as a folder. Is only called when: - *
    - *
  • {@link #doGetType} returns {@link FileType#IMAGINARY}.
  • - *
  • The parent folder exists and is writable, or this file is the root of the file system.
  • - *
- * This implementation throws an exception. - * - * @throws Exception if an error occurs. - */ - protected void doCreateFolder() throws Exception { - throw new FileSystemException("vfs.provider/create-folder-not-supported.error"); - } - - /** - * Deletes the file. Is only called when: - *
    - *
  • {@link #doGetType} does not return {@link FileType#IMAGINARY}.
  • - *
  • {@link #doIsWriteable} returns true.
  • - *
  • This file has no children, if a folder.
  • - *
- * This implementation throws an exception. - * - * @throws Exception if an error occurs. - */ - protected void doDelete() throws Exception { - throw new FileSystemException("vfs.provider/delete-not-supported.error"); - } - - /** - * Detaches this file object from its file resource. - *

- * Called when this file is closed. Note that the file object may be reused later, so should be able to be - * reattached. - *

- *

- * This implementation does nothing. - *

- * - * @throws Exception if an error occurs. - */ - protected void doDetach() throws Exception { - // noop - } - - /** - * Returns the attributes of this file. Is only called if {@link #doGetType} does not return - * {@link FileType#IMAGINARY}. - *

- * This implementation always returns an empty map. - *

- * - * @return The attributes of the file. - * @throws Exception if an error occurs. - */ - protected Map doGetAttributes() throws Exception { - return Collections.emptyMap(); - } - - /** - * Returns the certificates used to sign this file. Is only called if {@link #doGetType} does not return - * {@link FileType#IMAGINARY}. - *

- * This implementation always returns null. - *

- * - * @return The certificates used to sign the file. - * @throws Exception if an error occurs. - */ - protected Certificate[] doGetCertificates() throws Exception { - return null; - } - - /** - * Returns the size of the file content (in bytes). Is only called if {@link #doGetType} returns - * {@link FileType#FILE}. - * - * @return The size of the file in bytes. - * @throws Exception if an error occurs. - */ - protected abstract long doGetContentSize() throws Exception; - - /** - * Creates an input stream to read the file content from. Is only called if {@link #doGetType} returns - * {@link FileType#FILE}. - *

- * It is guaranteed that there are no open output streams for this file when this method is called. - *

- *

- * The returned stream does not have to be buffered. - *

- * - * @return An InputStream to read the file content. - * @throws Exception if an error occurs. - */ - protected InputStream doGetInputStream() throws Exception { - // Backward compatibility. - return doGetInputStream(DEFAULT_BUFFER_SIZE); - } - - /** - * Creates an input stream to read the file content from. Is only called if {@link #doGetType} returns - * {@link FileType#FILE}. - *

- * It is guaranteed that there are no open output streams for this file when this method is called. - *

- *

- * The returned stream does not have to be buffered. - *

- * @param bufferSize Buffer size hint. - * @return An InputStream to read the file content. - * @throws Exception if an error occurs. - */ - protected InputStream doGetInputStream(final int bufferSize) throws Exception { - throw new UnsupportedOperationException(DO_GET_INPUT_STREAM_INT); - } - - /** - * Returns the last modified time of this file. Is only called if {@link #doGetType} does not return - *

- * This implementation throws an exception. - *

- * - * @return The last modification time. - * @throws Exception if an error occurs. - */ - protected long doGetLastModifiedTime() throws Exception { - throw new FileSystemException("vfs.provider/get-last-modified-not-supported.error"); - } - - /** - * Creates an output stream to write the file content to. Is only called if: - *
    - *
  • {@link #doIsWriteable} returns true. - *
  • {@link #doGetType} returns {@link FileType#FILE}, or {@link #doGetType} returns {@link FileType#IMAGINARY}, - * and the file's parent exists and is a folder. - *
- * It is guaranteed that there are no open stream (input or output) for this file when this method is called. - *

- * The returned stream does not have to be buffered. - *

- *

- * This implementation throws an exception. - *

- * - * @param bAppend true if the file should be appended to, false if it should be overwritten. - * @return An OutputStream to write to the file. - * @throws Exception if an error occurs. - */ - protected OutputStream doGetOutputStream(final boolean bAppend) throws Exception { - throw new FileSystemException("vfs.provider/write-not-supported.error"); - } - - /** - * Creates access to the file for random i/o. Is only called if {@link #doGetType} returns {@link FileType#FILE}. - *

- * It is guaranteed that there are no open output streams for this file when this method is called. - *

- * - * @param mode The mode to access the file. - * @return The RandomAccessContext. - * @throws Exception if an error occurs. - */ - protected RandomAccessContent doGetRandomAccessContent(final RandomAccessMode mode) throws Exception { - throw new FileSystemException("vfs.provider/random-access-not-supported.error"); - } - - /** - * Determines the type of this file. Must not return null. The return value of this method is cached, so the - * implementation can be expensive. - * - * @return the type of the file. - * @throws Exception if an error occurs. - */ - protected abstract FileType doGetType() throws Exception; - - /** - * Determines if this file is executable. Is only called if {@link #doGetType} does not return - * {@link FileType#IMAGINARY}. - *

- * This implementation always returns false. - *

- * - * @return true if the file is executable, false otherwise. - * @throws Exception if an error occurs. - */ - protected boolean doIsExecutable() throws Exception { - return false; - } - - /** - * Determines if this file is hidden. Is only called if {@link #doGetType} does not return - * {@link FileType#IMAGINARY}. - *

- * This implementation always returns false. - *

- * - * @return true if the file is hidden, false otherwise. - * @throws Exception if an error occurs. - */ - protected boolean doIsHidden() throws Exception { - return false; - } - - /** - * Determines if this file can be read. Is only called if {@link #doGetType} does not return - * {@link FileType#IMAGINARY}. - *

- * This implementation always returns true. - *

- * - * @return true if the file is readable, false otherwise. - * @throws Exception if an error occurs. - */ - protected boolean doIsReadable() throws Exception { - return true; - } - - /** - * Checks if this fileObject is the same file as {@code destFile} just with a different name. E.g. for - * case-insensitive file systems like Windows. - * - * @param destFile The file to compare to. - * @return true if the FileObjects are the same. - * @throws FileSystemException if an error occurs. - */ - protected boolean doIsSameFile(final FileObject destFile) throws FileSystemException { - return false; - } - - /** - * Determines if this file is a symbolic link. Is only called if {@link #doGetType} does not return - * {@link FileType#IMAGINARY}. - *

- * This implementation always returns false. - *

- * - * @return true if the file is readable, false otherwise. - * @throws Exception if an error occurs. - * @since 2.4 - */ - protected boolean doIsSymbolicLink() throws Exception { - return false; - } - - /** - * Determines if this file can be written to. Is only called if {@link #doGetType} does not return - * {@link FileType#IMAGINARY}. - *

- * This implementation always returns true. - *

- * - * @return true if the file is writable. - * @throws Exception if an error occurs. - */ - protected boolean doIsWriteable() throws Exception { - return true; - } - - /** - * Lists the children of this file. Is only called if {@link #doGetType} returns {@link FileType#FOLDER}. The return - * value of this method is cached, so the implementation can be expensive. - * - * @return a possible empty String array if the file is a directory or null or an exception if the file is not a - * directory or can't be read. - * @throws Exception if an error occurs. - */ - protected abstract String[] doListChildren() throws Exception; - - /** - * Lists the children of this file. - *

- * Is only called if {@link #doGetType} returns {@link FileType#FOLDER}. - *

- *

- * The return value of this method is cached, so the implementation can be expensive. - * Other than {@code doListChildren} you could return FileObject's to e.g. reinitialize the type of the file. - *

- *

- * (Introduced for WebDAV: "permission denied on resource" during getType()) - *

- * - * @return The children of this FileObject. - * @throws Exception if an error occurs. - */ - protected FileObject[] doListChildrenResolved() throws Exception { - return null; - } - - /** - * Removes an attribute of this file. - *

- * Is only called if {@link #doGetType} does not return {@link FileType#IMAGINARY}. - *

- *

- * This implementation throws an exception. - *

- * - * @param attrName The name of the attribute to remove. - * @throws Exception if an error occurs. - * @since 2.0 - */ - protected void doRemoveAttribute(final String attrName) throws Exception { - throw new FileSystemException("vfs.provider/remove-attribute-not-supported.error"); - } - - /** - * Renames the file. - *

- * Is only called when: - *

- *
    - *
  • {@link #doIsWriteable} returns true.
  • - *
- *

- * This implementation throws an exception. - *

- * - * @param newFile A FileObject with the new file name. - * @throws Exception if an error occurs. - */ - protected void doRename(final FileObject newFile) throws Exception { - throw new FileSystemException("vfs.provider/rename-not-supported.error"); - } - - /** - * Sets an attribute of this file. - *

- * Is only called if {@link #doGetType} does not return {@link FileType#IMAGINARY}. - *

- *

- * This implementation throws an exception. - *

- * - * @param attrName The attribute name. - * @param value The value to be associated with the attribute name. - * @throws Exception if an error occurs. - */ - protected void doSetAttribute(final String attrName, final Object value) throws Exception { - throw new FileSystemException("vfs.provider/set-attribute-not-supported.error"); - } - - /** - * Make the file executable. - *

- * Only called if {@link #doGetType} does not return {@link FileType#IMAGINARY}. - *

- *

- * This implementation returns false. - *

- * - * @param executable True to allow access, false to disallow. - * @param ownerOnly If {@code true}, the permission applies only to the owner; otherwise, it applies to everybody. - * @return true if the operation succeeded. - * @throws Exception Any Exception thrown is wrapped in FileSystemException. - * @see #setExecutable(boolean, boolean) - * @since 2.1 - */ - protected boolean doSetExecutable(final boolean executable, final boolean ownerOnly) throws Exception { - return false; - } - - /** - * Sets the last modified time of this file. - *

- * Is only called if {@link #doGetType} does not return {@link FileType#IMAGINARY}. - *

- *

- * This implementation throws an exception. - *

- * - * @param modtime The last modification time. - * @return true if the time was set. - * @throws Exception Any Exception thrown is wrapped in FileSystemException. - */ - protected boolean doSetLastModifiedTime(final long modtime) throws Exception { - throw new FileSystemException("vfs.provider/set-last-modified-not-supported.error"); - } - - /** - * Make the file or folder readable. - *

- * Only called if {@link #doGetType} does not return {@link FileType#IMAGINARY}. - *

- *

- * This implementation returns false. - *

- * - * @param readable True to allow access, false to disallow - * @param ownerOnly If {@code true}, the permission applies only to the owner; otherwise, it applies to everybody. - * @return true if the operation succeeded - * @throws Exception Any Exception thrown is wrapped in FileSystemException. - * @see #setReadable(boolean, boolean) - * @since 2.1 - */ - protected boolean doSetReadable(final boolean readable, final boolean ownerOnly) throws Exception { - return false; - } - - /** - * Make the file or folder writable. - *

- * Only called if {@link #doGetType} does not return {@link FileType#IMAGINARY}. - *

- * - * @param writable True to allow access, false to disallow - * @param ownerOnly If {@code true}, the permission applies only to the owner; otherwise, it applies to everybody. - * @return true if the operation succeeded - * @throws Exception Any Exception thrown is wrapped in FileSystemException. - * @see #setWritable(boolean, boolean) - * @since 2.1 - */ - protected boolean doSetWritable(final boolean writable, final boolean ownerOnly) throws Exception { - return false; - } - - /** - * Called when the output stream for this file is closed. - * - * @throws Exception if an error occurs. - */ - protected void endOutput() throws Exception { - if (getType() == FileType.IMAGINARY) { - // File was created - handleCreate(FileType.FILE); - } else { - // File has changed - onChange(); - } - } - - /** - * Determines if the file exists. - * - * @return true if the file exists, false otherwise, - * @throws FileSystemException if an error occurs. - */ - @Override - public boolean exists() throws FileSystemException { - return getType() != FileType.IMAGINARY; - } - - private FileName[] extractNames(final FileObject[] objects) { - if (objects == null) { - return null; - } - return Stream.of(objects).filter(Objects::nonNull).map(FileObject::getName).toArray(FileName[]::new); - } - - @Override - protected void finalize() throws Throwable { - fileSystem.fileObjectDestroyed(this); - - super.finalize(); - } - - /** - * Finds the set of matching descendants of this file, in depthwise order. - * - * @param selector The FileSelector. - * @return list of files or null if the base file (this object) do not exist - * @throws FileSystemException if an error occurs. - */ - @Override - public FileObject[] findFiles(final FileSelector selector) throws FileSystemException { - final List list = this.listFiles(selector); - return list == null ? null : list.toArray(EMPTY_ARRAY); - } - - /** - * Traverses the descendants of this file, and builds a list of selected files. - * - * @param selector The FileSelector. - * @param depthwise if true files are added after their descendants, before otherwise. - * @param selected A List of the located FileObjects. - * @throws FileSystemException if an error occurs. - */ - @Override - public void findFiles(final FileSelector selector, final boolean depthwise, final List selected) - throws FileSystemException { - try { - if (exists()) { - // Traverse starting at this file - final DefaultFileSelectorInfo info = new DefaultFileSelectorInfo(); - info.setBaseFolder(this); - info.setDepth(0); - info.setFile(this); - traverse(info, selector, depthwise, selected); - } - } catch (final Exception e) { - throw new FileSystemException("vfs.provider/find-files.error", fileName, e); - } - } - - /** - * Returns the file system this file belongs to. - * - * @return The FileSystem this file is associated with. - */ - protected AFS getAbstractFileSystem() { - return fileSystem; - } - - /** - * Returns a child of this file. - * - * @param name The name of the child to locate. - * @return The FileObject for the file or null if the child does not exist. - * @throws FileSystemException if an error occurs. - */ - @Override - public FileObject getChild(final String name) throws FileSystemException { - // TODO - use a hashtable when there are a large number of children - final FileObject[] children = getChildren(); - for (final FileObject element : children) { - final FileName child = element.getName(); - final String childBaseName = child.getBaseName(); - // TODO - use a comparator to compare names - if (childBaseName.equals(name) || UriParser.decode(childBaseName).equals(name)) { - return resolveFile(child); - } - } - return null; - } - - /** - * Returns the children of the file. - * - * @return an array of FileObjects, one per child. - * @throws FileSystemException if an error occurs. - */ - @Override - public FileObject[] getChildren() throws FileSystemException { - synchronized (fileSystem) { - // VFS-210 - if (!fileSystem.hasCapability(Capability.LIST_CHILDREN)) { - throw new FileNotFolderException(fileName); - } - - /* - * VFS-210 if (!getType().hasChildren()) { throw new - * FileSystemException("vfs.provider/list-children-not-folder.error", name); } - */ - attach(); - - // Use cached info, if present - if (children != null) { - return resolveFiles(children); - } - - // allow the filesystem to return resolved children. e.g. prefill type for webdav - final FileObject[] childrenObjects; - try { - childrenObjects = doListChildrenResolved(); - children = extractNames(childrenObjects); - } catch (final FileSystemException exc) { - // VFS-210 - throw exc; - } catch (final Exception exc) { - throw new FileSystemException("vfs.provider/list-children.error", exc, fileName); - } - - if (childrenObjects != null) { - return childrenObjects; - } - - // List the children - final String[] files; - try { - files = doListChildren(); - } catch (final FileSystemException exc) { - // VFS-210 - throw exc; - } catch (final Exception exc) { - throw new FileSystemException("vfs.provider/list-children.error", exc, fileName); - } - - if (files == null) { - // VFS-210 - // honor the new doListChildren contract - // return null; - throw new FileNotFolderException(fileName); - } - if (files.length == 0) { - // No children - children = FileName.EMPTY_ARRAY; - } else { - // Create file objects for the children - final FileName[] cache = new FileName[files.length]; - for (int i = 0; i < files.length; i++) { - final String file = "./" + files[i]; // VFS-741: assume scheme prefix is file name only - cache[i] = fileSystem.getFileSystemManager().resolveName(fileName, file, NameScope.CHILD); - } - // VFS-285: only assign the children file names after all of them have been - // resolved successfully to prevent an inconsistent internal state - children = cache; - } - - return resolveFiles(children); - } - } - - /** - * Returns the file's content. - * - * @return the FileContent for this FileObject. - * @throws FileSystemException if an error occurs. - */ - @Override - public FileContent getContent() throws FileSystemException { - synchronized (fileSystem) { - attach(); - if (content == null) { - content = doCreateFileContent(); - } - return content; - } - } - - /** - * Creates the FileContentInfo factory. - * - * @return The FileContentInfoFactory. - */ - protected FileContentInfoFactory getFileContentInfoFactory() { - return fileSystem.getFileSystemManager().getFileContentInfoFactory(); - } - - /** - * @return FileOperations interface that provides access to the operations API. - * @throws FileSystemException if an error occurs. - */ - @Override - public FileOperations getFileOperations() throws FileSystemException { - if (operations == null) { - operations = new DefaultFileOperations(this); - } - - return operations; - } - - /** - * Returns the file system this file belongs to. - * - * @return The FileSystem this file is associated with. - */ - @Override - public FileSystem getFileSystem() { - return fileSystem; - } - - /** - * Returns an input stream to use to read the content of the file. - * - * @return The InputStream to access this file's content. - * @throws FileSystemException if an error occurs. - */ - public InputStream getInputStream() throws FileSystemException { - return getInputStream(DEFAULT_BUFFER_SIZE); - } - - /** - * Returns an input stream to use to read the content of the file. - * - * @param bufferSize buffer size hint. - * @return The InputStream to access this file's content. - * @throws FileSystemException if an error occurs. - */ - public InputStream getInputStream(final int bufferSize) throws FileSystemException { - // Get the raw input stream - try { - return doGetInputStream(bufferSize); - } catch (final org.apache.commons.vfs2.FileNotFoundException | FileNotFoundException exc) { - throw new org.apache.commons.vfs2.FileNotFoundException(fileName, exc); - } catch (final FileSystemException exc) { - throw exc; - } catch (final UnsupportedOperationException uoe) { - // TODO Remove for 3.0 - // Backward compatibility for subclasses before 2.5.0 - if (DO_GET_INPUT_STREAM_INT.equals(uoe.getMessage())) { - try { - // Invoke old API. - return doGetInputStream(); - } catch (final Exception e) { - if (e instanceof FileSystemException) { - throw (FileSystemException) e; - } - throw new FileSystemException("vfs.provider/read.error", fileName, e); - } - } - throw uoe; - } catch (final Exception exc) { - throw new FileSystemException("vfs.provider/read.error", fileName, exc); - } - } - - /** - * Returns the name of the file. - * - * @return The FileName, never {@code null}. - */ - @Override - public FileName getName() { - return fileName; - } - - // TODO: remove this method for the next major version as it is unused - /** - * Prepares this file for writing. Makes sure it is either a file, or its parent folder exists. Returns an output - * stream to use to write the content of the file to. - * - * @return An OutputStream where the new contents of the file can be written. - * @throws FileSystemException if an error occurs. - */ - public OutputStream getOutputStream() throws FileSystemException { - return getOutputStream(false); - } - - // TODO: mark this method as `final` and package-private for the next major version because - // it shouldn't be used from anywhere other than `DefaultFileContent` - /** - * Prepares this file for writing. Makes sure it is either a file, or its parent folder exists. Returns an output - * stream to use to write the content of the file to. - * - * @param bAppend true when append to the file. - * Note: If the underlying file system does not support appending, a FileSystemException is thrown. - * @return An OutputStream where the new contents of the file can be written. - * @throws FileSystemException if an error occurs; for example: - * bAppend is true, and the underlying FileSystem does not support it - */ - public OutputStream getOutputStream(final boolean bAppend) throws FileSystemException { - /* - * VFS-210 if (getType() != FileType.IMAGINARY && !getType().hasContent()) { throw new - * FileSystemException("vfs.provider/write-not-file.error", name); } if (!isWriteable()) { throw new - * FileSystemException("vfs.provider/write-read-only.error", name); } - */ - - if (bAppend && !fileSystem.hasCapability(Capability.APPEND_CONTENT)) { - throw new FileSystemException("vfs.provider/write-append-not-supported.error", fileName); - } - - if (getType() == FileType.IMAGINARY) { - // Does not exist - make sure parent does - final FileObject parent = getParent(); - if (parent != null) { - parent.createFolder(); - } - } - - // Get the raw output stream - try { - return doGetOutputStream(bAppend); - } catch (final RuntimeException re) { - throw re; - } catch (final Exception exc) { - throw new FileSystemException("vfs.provider/write.error", exc, fileName); - } - } - - /** - * Returns the parent of the file. - * - * @return the parent FileObject. - * @throws FileSystemException if an error occurs. - */ - @Override - public FileObject getParent() throws FileSystemException { - // equals is not implemented :-/ - if (this.compareTo(fileSystem.getRoot()) == 0) { - if (fileSystem.getParentLayer() == null) { - // Root file has no parent - return null; - } - // Return the parent of the parent layer - return fileSystem.getParentLayer().getParent(); - } - - synchronized (fileSystem) { - // Locate the parent of this file - if (parent == null) { - final FileName name = fileName.getParent(); - if (name == null) { - return null; - } - parent = fileSystem.resolveFile(name); - } - return parent; - } - } - - /** - * Returns the receiver as a URI String for public display, like, without a password. - * - * @return A URI String without a password, never {@code null}. - */ - @Override - public String getPublicURIString() { - return fileName.getFriendlyURI(); - } - - /** - * Returns an input/output stream to use to read and write the content of the file in and random manner. - * - * @param mode The RandomAccessMode. - * @return The RandomAccessContent. - * @throws FileSystemException if an error occurs. - */ - public RandomAccessContent getRandomAccessContent(final RandomAccessMode mode) throws FileSystemException { - // - // VFS-210 if (!getType().hasContent()) { throw new FileSystemException("vfs.provider/read-not-file.error", - // name); } - // - if (mode.requestRead()) { - if (!fileSystem.hasCapability(Capability.RANDOM_ACCESS_READ)) { - throw new FileSystemException("vfs.provider/random-access-read-not-supported.error"); - } - if (!isReadable()) { - throw new FileSystemException("vfs.provider/read-not-readable.error", fileName); - } - } - - if (mode.requestWrite()) { - if (!fileSystem.hasCapability(Capability.RANDOM_ACCESS_WRITE)) { - throw new FileSystemException("vfs.provider/random-access-write-not-supported.error"); - } - if (!isWriteable()) { - throw new FileSystemException("vfs.provider/write-read-only.error", fileName); - } - } - - // Get the raw input stream - try { - return doGetRandomAccessContent(mode); - } catch (final Exception exc) { - throw new FileSystemException("vfs.provider/random-access.error", fileName, exc); - } - } - - /** - * Returns the file's type. - * - * @return The FileType. - * @throws FileSystemException if an error occurs. - */ - @Override - public FileType getType() throws FileSystemException { - synchronized (fileSystem) { - attach(); - - // VFS-210: get the type only if requested for - try { - if (type == null) { - setFileType(doGetType()); - } - if (type == null) { - setFileType(FileType.IMAGINARY); - } - } catch (final Exception e) { - throw new FileSystemException("vfs.provider/get-type.error", e, fileName); - } - - return type; - } - } - - /** - * Returns a URL representation of the file. - * - * @return The URL representation of the file. - * @throws FileSystemException if an error occurs. - */ - @Override - public URL getURL() throws FileSystemException { - try { - return AccessController.doPrivileged((PrivilegedExceptionAction) () -> { - final StringBuilder buf = new StringBuilder(); - final String scheme = UriParser.extractScheme(fileSystem.getContext().getFileSystemManager().getSchemes(), fileName.getURI(), buf); - return new URL(scheme, "", -1, buf.toString(), - new DefaultURLStreamHandler(fileSystem.getContext(), fileSystem.getFileSystemOptions())); - }); - } catch (final PrivilegedActionException e) { - throw new FileSystemException("vfs.provider/get-url.error", fileName, e.getException()); - } - } - - /** - * Called when this file is changed. - *

- * This will only happen if you monitor the file using {@link org.apache.commons.vfs2.FileMonitor}. - *

- * - * @throws Exception if an error occurs. - */ - protected void handleChanged() throws Exception { - // Notify the file system - fileSystem.fireFileChanged(this); - } - - /** - * Called when this file is created. Updates cached info and notifies the parent and file system. - * - * @param newType The type of the file. - * @throws Exception if an error occurs. - */ - protected void handleCreate(final FileType newType) throws Exception { - synchronized (fileSystem) { - if (attached) { - // Fix up state - injectType(newType); - - removeChildrenCache(); - - // Notify subclass - onChange(); - } - - // Notify parent that its child list may no longer be valid - notifyParent(this.getName(), newType); - - // Notify the file system - fileSystem.fireFileCreated(this); - } - } - - /** - * Called when this file is deleted. Updates cached info and notifies subclasses, parent and file system. - * - * @throws Exception if an error occurs. - */ - protected void handleDelete() throws Exception { - synchronized (fileSystem) { - if (attached) { - // Fix up state - injectType(FileType.IMAGINARY); - removeChildrenCache(); - - // Notify subclass - onChange(); - } - - // Notify parent that its child list may no longer be valid - notifyParent(this.getName(), FileType.IMAGINARY); - - // Notify the file system - fileSystem.fireFileDeleted(this); - } - } - - /** - * This method is meant to add an object where this object holds a strong reference then. E.g. an archive-file system - * creates a list of all children and they shouldn't get garbage collected until the container is garbage collected - * - * @param strongRef The Object to add. - */ - // TODO should this be a FileObject? - public void holdObject(final Object strongRef) { - if (objects == null) { - objects = new ArrayList<>(INITIAL_LIST_SIZE); - } - objects.add(strongRef); - } - - /** - * Sets the file type. - * - * @param fileType the file type. - */ - protected void injectType(final FileType fileType) { - setFileType(fileType); - } - - /** - * Check if the internal state is "attached". - * - * @return true if this is the case - */ - @Override - public boolean isAttached() { - return attached; - } - - /** - * Check if the content stream is open. - * - * @return true if this is the case - */ - @Override - public boolean isContentOpen() { - if (content == null) { - return false; - } - - return content.isOpen(); - } - - /** - * Determines if this file is executable. - * - * @return {@code true} if this file is executable, {@code false} if not. - * @throws FileSystemException On error determining if this file exists. - */ - @Override - public boolean isExecutable() throws FileSystemException { - try { - return exists() && doIsExecutable(); - } catch (final Exception exc) { - throw new FileSystemException("vfs.provider/check-is-executable.error", fileName, exc); - } - } - - /** - * Checks if this file is a regular file by using its file type. - * - * @return true if this file is a regular file. - * @throws FileSystemException if an error occurs. - * @see #getType() - * @see FileType#FILE - */ - @Override - public boolean isFile() throws FileSystemException { - // Use equals instead of == to avoid any class loader worries. - return FileType.FILE.equals(this.getType()); - } - - /** - * Checks if this file is a folder by using its file type. - * - * @return true if this file is a regular file. - * @throws FileSystemException if an error occurs. - * @see #getType() - * @see FileType#FOLDER - */ - @Override - public boolean isFolder() throws FileSystemException { - // Use equals instead of == to avoid any class loader worries. - return FileType.FOLDER.equals(this.getType()); - } - - /** - * Determines if this file can be read. - * - * @return true if the file is a hidden file, false otherwise. - * @throws FileSystemException if an error occurs. - */ - @Override - public boolean isHidden() throws FileSystemException { - try { - return exists() && doIsHidden(); - } catch (final Exception exc) { - throw new FileSystemException("vfs.provider/check-is-hidden.error", fileName, exc); - } - } - - /** - * Determines if this file can be read. - * - * @return true if the file can be read, false otherwise. - * @throws FileSystemException if an error occurs. - */ - @Override - public boolean isReadable() throws FileSystemException { - try { - return exists() && doIsReadable(); - } catch (final Exception exc) { - throw new FileSystemException("vfs.provider/check-is-readable.error", fileName, exc); - } - } - - /** - * Checks if this fileObject is the same file as {@code destFile} just with a different name. E.g. for - * case-insensitive file systems like windows. - * - * @param destFile The file to compare to. - * @return true if the FileObjects are the same. - * @throws FileSystemException if an error occurs. - */ - protected boolean isSameFile(final FileObject destFile) throws FileSystemException { - attach(); - return doIsSameFile(destFile); - } - - /** - * Determines if this file can be read. - * - * @return true if the file can be read, false otherwise. - * @throws FileSystemException if an error occurs. - * @since 2.4 - */ - @Override - public boolean isSymbolicLink() throws FileSystemException { - try { - return exists() && doIsSymbolicLink(); - } catch (final Exception exc) { - throw new FileSystemException("vfs.provider/check-is-symbolic-link.error", fileName, exc); - } - } - - /** - * Determines if this file can be written to. - * - * @return true if the file can be written to, false otherwise. - * @throws FileSystemException if an error occurs. - */ - @Override - public boolean isWriteable() throws FileSystemException { - try { - if (exists()) { - return doIsWriteable(); - } - final FileObject parent = getParent(); - if (parent != null) { - return parent.isWriteable(); - } - return true; - } catch (final Exception exc) { - throw new FileSystemException("vfs.provider/check-is-writable.error", fileName, exc); - } - } - - /** - * Returns an iterator over a set of all FileObject in this file object. - * - * @return an Iterator. - */ - @Override - public Iterator iterator() { - try { - return listFiles(Selectors.SELECT_ALL).iterator(); - } catch (final FileSystemException e) { - throw new IllegalStateException(e); - } - } - - /** - * Lists the set of matching descendants of this file, in depthwise order. - * - * @param selector The FileSelector. - * @return list of files or null if the base file (this object) do not exist or the {@code selector} is null - * @throws FileSystemException if an error occurs. - */ - public List listFiles(final FileSelector selector) throws FileSystemException { - if (!exists() || selector == null) { - return null; - } - - final ArrayList list = new ArrayList<>(); - this.findFiles(selector, true, list); - return list; - } - - /** - * Moves (rename) the file to another one. - * - * @param destFile The target FileObject. - * @throws FileSystemException if an error occurs. - */ - @Override - public void moveTo(final FileObject destFile) throws FileSystemException { - if (canRenameTo(destFile)) { - if (!getParent().isWriteable()) { - throw new FileSystemException("vfs.provider/rename-parent-read-only.error", getName(), - getParent().getName()); - } - } else if (!isWriteable()) { - throw new FileSystemException("vfs.provider/rename-read-only.error", getName()); - } - - if (destFile.exists() && !isSameFile(destFile)) { - destFile.deleteAll(); - // throw new FileSystemException("vfs.provider/rename-dest-exists.error", destFile.getName()); - } - - if (canRenameTo(destFile)) { - // issue rename on same filesystem - try { - attach(); - // remember type to avoid attach - final FileType srcType = getType(); - - doRename(destFile); - - FileObjectUtils.getAbstractFileObject(destFile).handleCreate(srcType); - destFile.close(); // now the destFile is no longer imaginary. force reattach. - - handleDelete(); // fire delete-events. This file-object (src) is like deleted. - } catch (final RuntimeException re) { - throw re; - } catch (final Exception exc) { - throw new FileSystemException("vfs.provider/rename.error", exc, getName(), destFile.getName()); - } - } else { - // different fs - do the copy/delete stuff - - destFile.copyFrom(this, Selectors.SELECT_SELF); - - if ((destFile.getType().hasContent() - && destFile.getFileSystem().hasCapability(Capability.SET_LAST_MODIFIED_FILE) - || destFile.getType().hasChildren() - && destFile.getFileSystem().hasCapability(Capability.SET_LAST_MODIFIED_FOLDER)) - && fileSystem.hasCapability(Capability.GET_LAST_MODIFIED)) { - destFile.getContent().setLastModifiedTime(this.getContent().getLastModifiedTime()); - } - - deleteSelf(); - } - - } - - /** - * Called after this file-object closed all its streams. - */ - protected void notifyAllStreamsClosed() { - // noop - } - - /** - * Notify the parent of a change to its children, when a child is created or deleted. - * - * @param childName The name of the child. - * @param newType The type of the child. - * @throws Exception if an error occurs. - */ - private void notifyParent(final FileName childName, final FileType newType) throws Exception { - if (parent == null) { - final FileName parentName = fileName.getParent(); - if (parentName != null) { - // Locate the parent, if it is cached - parent = fileSystem.getFileFromCache(parentName); - } - } - - if (parent != null) { - FileObjectUtils.getAbstractFileObject(parent).childrenChanged(childName, newType); - } - } - - /** - * Called when the type or content of this file changes. - *

- * This implementation does nothing. - *

- * - * @throws Exception if an error occurs. - */ - protected void onChange() throws Exception { - // noop - } - - /** - * Called when the children of this file change. Allows subclasses to refresh any cached information about the - * children of this file. - *

- * This implementation does nothing. - *

- * - * @param child The name of the child that changed. - * @param newType The type of the file. - * @throws Exception if an error occurs. - */ - protected void onChildrenChanged(final FileName child, final FileType newType) throws Exception { - // noop - } - - /** - * This will prepare the fileObject to get resynchronized with the underlying file system if required. - * - * @throws FileSystemException if an error occurs. - */ - @Override - public void refresh() throws FileSystemException { - // Detach from the file - try { - detach(); - } catch (final Exception e) { - throw new FileSystemException("vfs.provider/resync.error", fileName, e); - } - } - - private void removeChildrenCache() { - children = null; - } - - private FileObject resolveFile(final FileName child) throws FileSystemException { - return fileSystem.resolveFile(child); - } - - /** - * Finds a file, relative to this file. - * - * @param path The path of the file to locate. Can either be a relative path, which is resolved relative to this - * file, or an absolute path, which is resolved relative to the file system that contains this file. - * @return The FileObject. - * @throws FileSystemException if an error occurs. - */ - @Override - public FileObject resolveFile(final String path) throws FileSystemException { - final FileName otherName = fileSystem.getFileSystemManager().resolveName(fileName, path); - return fileSystem.resolveFile(otherName); - } - - /** - * Returns a child by name. - * - * @param name The name of the child to locate. - * @param scope the NameScope. - * @return The FileObject for the file or null if the child does not exist. - * @throws FileSystemException if an error occurs. - */ - @Override - public FileObject resolveFile(final String name, final NameScope scope) throws FileSystemException { - // return fs.resolveFile(this.name.resolveName(name, scope)); - return fileSystem.resolveFile(fileSystem.getFileSystemManager().resolveName(fileName, name, scope)); - } - - private FileObject[] resolveFiles(final FileName[] children) throws FileSystemException { - if (children == null) { - return null; - } - - final FileObject[] objects = new FileObject[children.length]; - for (int iterChildren = 0; iterChildren < children.length; iterChildren++) { - objects[iterChildren] = resolveFile(children[iterChildren]); - } - - return objects; - } - - @Override - public boolean setExecutable(final boolean readable, final boolean ownerOnly) throws FileSystemException { - try { - return exists() && doSetExecutable(readable, ownerOnly); - } catch (final Exception exc) { - throw new FileSystemException("vfs.provider/set-executable.error", fileName, exc); - } - } - - private void setFileType(final FileType type) { - if (type != null && type != FileType.IMAGINARY) { - Uncheck.run(() -> fileName.setType(type)); - } - this.type = type; - } - - @Override - public boolean setReadable(final boolean readable, final boolean ownerOnly) throws FileSystemException { - try { - return exists() && doSetReadable(readable, ownerOnly); - } catch (final Exception exc) { - throw new FileSystemException("vfs.provider/set-readable.error", fileName, exc); - } - } - - @Override - public boolean setWritable(final boolean readable, final boolean ownerOnly) throws FileSystemException { - try { - return exists() && doSetWritable(readable, ownerOnly); - } catch (final Exception exc) { - throw new FileSystemException("vfs.provider/set-writable.error", fileName, exc); - } - } - - /** - * Returns the URI as a String. - * - * @return Returns the URI as a String. - */ - @Override - public String toString() { - return fileName.getURI(); - } -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.vfs2.provider; + +import java.io.BufferedInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URL; +import java.security.AccessController; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.security.cert.Certificate; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Stream; + +import org.apache.commons.io.function.Uncheck; +import org.apache.commons.vfs2.Capability; +import org.apache.commons.vfs2.FileContent; +import org.apache.commons.vfs2.FileContentInfoFactory; +import org.apache.commons.vfs2.FileName; +import org.apache.commons.vfs2.FileNotFolderException; +import org.apache.commons.vfs2.FileObject; +import org.apache.commons.vfs2.FileSelector; +import org.apache.commons.vfs2.FileSystem; +import org.apache.commons.vfs2.FileSystemException; +import org.apache.commons.vfs2.FileType; +import org.apache.commons.vfs2.NameScope; +import org.apache.commons.vfs2.RandomAccessContent; +import org.apache.commons.vfs2.Selectors; +import org.apache.commons.vfs2.operations.DefaultFileOperations; +import org.apache.commons.vfs2.operations.FileOperations; +import org.apache.commons.vfs2.util.FileObjectUtils; +import org.apache.commons.vfs2.util.RandomAccessMode; + +/** + * A partial file object implementation. + * + * TODO - Chop this class up - move all the protected methods to several interfaces, so that structure and content can + * be separately overridden. + * + *

+ * TODO - Check caps in methods like getChildren(), etc, and give better error messages (eg 'this file type does not + * support listing children', vs 'this is not a folder') + *

+ * + * @param An AbstractFileSystem subclass + */ +public abstract class AbstractFileObject implements FileObject { + + /** + * Same as {@link BufferedInputStream}. + */ + public static final int DEFAULT_BUFFER_SIZE = 8192; + + private static final int INITIAL_LIST_SIZE = 5; + + private static final String DO_GET_INPUT_STREAM_INT = "doGetInputStream(int)"; + + /** + * Traverses a file. + */ + private static void traverse(final DefaultFileSelectorInfo fileInfo, final FileSelector selector, + final boolean depthwise, final List selected) throws Exception { + // Check the file itself + final FileObject file = fileInfo.getFile(); + final int index = selected.size(); + + // If the file is a folder, traverse it + if (file.getType().hasChildren() && selector.traverseDescendants(fileInfo)) { + final int curDepth = fileInfo.getDepth(); + fileInfo.setDepth(curDepth + 1); + + // Traverse the children + final FileObject[] children = file.getChildren(); + for (final FileObject child : children) { + fileInfo.setFile(child); + traverse(fileInfo, selector, depthwise, selected); + } + + fileInfo.setFile(file); + fileInfo.setDepth(curDepth); + } + + // Add the file if doing depthwise traversal + if (selector.includeFile(fileInfo)) { + if (depthwise) { + // Add this file after its descendants + selected.add(file); + } else { + // Add this file before its descendants + selected.add(index, file); + } + } + } + private final AbstractFileName fileName; + + private final AFS fileSystem; + private FileContent content; + // Cached info + private boolean attached; + + private FileType type; + private FileObject parent; + + // Changed to hold only the name of the children and let the object + // go into the global files cache + // private FileObject[] children; + private FileName[] children; + + private List objects; + + /** + * FileServices instance. + */ + private FileOperations operations; + + /** + * Constructs a new instance for subclasses. + * + * @param fileName the file name. + * @param fileSystem the file system. + */ + protected AbstractFileObject(final AbstractFileName fileName, final AFS fileSystem) { + this.fileName = fileName; + this.fileSystem = fileSystem; + fileSystem.fileObjectHanded(this); + } + + /** + * Attaches to the file. + * + * @throws FileSystemException if an error occurs. + */ + private void attach() throws FileSystemException { + synchronized (fileSystem) { + if (attached) { + return; + } + + try { + // Attach and determine the file type + doAttach(); + attached = true; + // now the type could already be injected by doAttach (e.g. from parent to child) + + /* + * VFS-210: determine the type when really asked fore if (type == null) { setFileType(doGetType()); } if + * (type == null) { setFileType(FileType.IMAGINARY); } + */ + } catch (final Exception exc) { + throw new FileSystemException("vfs.provider/get-type.error", exc, fileName); + } + + // fs.fileAttached(this); + } + } + + /** + * Queries the object if a simple rename to the file name of {@code newfile} is possible. + * + * @param newfile the new file name + * @return true if rename is possible + */ + @Override + public boolean canRenameTo(final FileObject newfile) { + return fileSystem == newfile.getFileSystem(); + } + + /** + * Notifies the file that its children have changed. + * + * @param childName The name of the child. + * @param newType The type of the child. + * @throws Exception if an error occurs. + */ + protected void childrenChanged(final FileName childName, final FileType newType) throws Exception { + // TODO - this may be called when not attached + + if (children != null && childName != null && newType != null) { + // TODO - figure out if children[] can be replaced by list + final ArrayList list = new ArrayList<>(Arrays.asList(children)); + if (newType.equals(FileType.IMAGINARY)) { + list.remove(childName); + } else { + list.add(childName); + } + children = list.toArray(FileName.EMPTY_ARRAY); + } + + // removeChildrenCache(); + onChildrenChanged(childName, newType); + } + + /** + * Closes this file, and its content. + * + * @throws FileSystemException if an error occurs. + */ + @Override + public void close() throws FileSystemException { + FileSystemException exc = null; + + synchronized (fileSystem) { + // Close the content + if (content != null) { + try { + content.close(); + content = null; + } catch (final FileSystemException e) { + exc = e; + } + } + + // Detach from the file + try { + detach(); + } catch (final Exception e) { + exc = new FileSystemException("vfs.provider/close.error", fileName, e); + } + + if (exc != null) { + throw exc; + } + } + } + + /** + * Compares two FileObjects (ignores case). + * + * @param file the object to compare. + * @return a negative integer, zero, or a positive integer when this object is less than, equal to, or greater than + * the given object. + */ + @Override + public int compareTo(final FileObject file) { + if (file == null) { + return 1; + } + return this.toString().compareToIgnoreCase(file.toString()); + } + + /** + * Copies another file to this file. + * + * @param file The FileObject to copy. + * @param selector The FileSelector. + * @throws FileSystemException if an error occurs. + */ + @Override + public void copyFrom(final FileObject file, final FileSelector selector) throws FileSystemException { + if (!FileObjectUtils.exists(file)) { + throw new FileSystemException("vfs.provider/copy-missing-file.error", file); + } + + // Locate the files to copy across + final ArrayList files = new ArrayList<>(); + file.findFiles(selector, false, files); + + // Copy everything across + for (final FileObject srcFile : files) { + // Determine the destination file + final String relPath = file.getName().getRelativeName(srcFile.getName()); + final FileObject destFile = resolveFile(relPath, NameScope.DESCENDENT_OR_SELF); + + // Clean up the destination file, if necessary + if (FileObjectUtils.exists(destFile) && destFile.getType() != srcFile.getType()) { + // The destination file exists, and is not of the same type, + // so delete it + // TODO - add a pluggable policy for deleting and overwriting existing files + destFile.deleteAll(); + } + + // Copy across + try { + if (srcFile.getType().hasContent()) { + FileObjectUtils.writeContent(srcFile, destFile); + } else if (srcFile.getType().hasChildren()) { + destFile.createFolder(); + } + } catch (final IOException e) { + throw new FileSystemException("vfs.provider/copy-file.error", e, srcFile, destFile); + } + } + } + + /** + * Creates this file, if it does not exist. + * + * @throws FileSystemException if an error occurs. + */ + @Override + public void createFile() throws FileSystemException { + synchronized (fileSystem) { + try { + // VFS-210: We do not want to trunc any existing file, checking for its existence is + // still required + if (exists() && !isFile()) { + throw new FileSystemException("vfs.provider/create-file.error", fileName); + } + + if (!exists()) { + try (FileContent content = getContent()) { + if (content != null) { + try (OutputStream ignored = content.getOutputStream()) { + // Avoids NPE on OutputStream#close() + } + } + } + } + } catch (final RuntimeException re) { + throw re; + } catch (final Exception e) { + throw new FileSystemException("vfs.provider/create-file.error", fileName, e); + } + } + } + + /** + * Creates this folder, if it does not exist. Also creates any ancestor files which do not exist. + * + * @throws FileSystemException if an error occurs. + */ + @Override + public void createFolder() throws FileSystemException { + synchronized (fileSystem) { + // VFS-210: we create a folder only if it does not already exist. So this check should be safe. + if (getType().hasChildren()) { + // Already exists as correct type + return; + } + if (getType() != FileType.IMAGINARY) { + throw new FileSystemException("vfs.provider/create-folder-mismatched-type.error", fileName); + } + /* + * VFS-210: checking for writable is not always possible as the security constraint might be more complex + * if (!isWriteable()) { throw new FileSystemException("vfs.provider/create-folder-read-only.error", name); + * } + */ + + // Traverse up the hierarchy and make sure everything is a folder + final FileObject parent = getParent(); + if (parent != null) { + parent.createFolder(); + } + + try { + // Create the folder + doCreateFolder(); + + // Update cached info + handleCreate(FileType.FOLDER); + } catch (final RuntimeException re) { + throw re; + } catch (final Exception exc) { + throw new FileSystemException("vfs.provider/create-folder.error", fileName, exc); + } + } + } + + /** + * Deletes this file. + *

+ * TODO - This will not fail if this is a non-empty folder. + *

+ * + * @return true if this object has been deleted + * @throws FileSystemException if an error occurs. + */ + @Override + public boolean delete() throws FileSystemException { + return delete(Selectors.SELECT_SELF) > 0; + } + + /** + * Deletes this file, and all children matching the {@code selector}. + * + * @param selector The FileSelector. + * @return the number of deleted files. + * @throws FileSystemException if an error occurs. + */ + @Override + public int delete(final FileSelector selector) throws FileSystemException { + int nuofDeleted = 0; + + /* + * VFS-210 if (getType() == FileType.IMAGINARY) { // File does not exist return nuofDeleted; } + */ + + // Locate all the files to delete + final ArrayList files = new ArrayList<>(); + findFiles(selector, true, files); + + // Delete 'em + for (final FileObject fileObject : files) { + final AbstractFileObject file = FileObjectUtils.getAbstractFileObject(fileObject); + // file.attach(); + // VFS-210: It seems impossible to me that findFiles will return a list with hidden files/directories + // in it, else it would not be hidden. Checking for the file-type seems ok in this case + // If the file is a folder, make sure all its children have been deleted + if (file.getType().hasChildren() && file.getChildren().length != 0) { + // Skip - as the selector forced us not to delete all files + continue; + } + // Delete the file + if (file.deleteSelf()) { + nuofDeleted++; + } + } + return nuofDeleted; + } + + /** + * Deletes this file and all children. Shorthand for {@code delete(Selectors.SELECT_ALL)} + * + * @return the number of deleted files. + * @throws FileSystemException if an error occurs. + * @see #delete(FileSelector) + * @see Selectors#SELECT_ALL + */ + @Override + public int deleteAll() throws FileSystemException { + return this.delete(Selectors.SELECT_ALL); + } + + /** + * Deletes this file, once all its children have been deleted + * + * @return true if this file has been deleted + * @throws FileSystemException if an error occurs. + */ + private boolean deleteSelf() throws FileSystemException { + synchronized (fileSystem) { + // It's possible to delete a read-only file if you have write-execute access to the directory + + /* + * VFS-210 if (getType() == FileType.IMAGINARY) { // File does not exist return false; } + */ + + try { + // Delete the file + doDelete(); + + // Update cached info + handleDelete(); + } catch (final RuntimeException re) { + throw re; + } catch (final Exception exc) { + throw new FileSystemException("vfs.provider/delete.error", exc, fileName); + } + + return true; + } + } + + /** + * Detaches this file, invalidating all cached info. This will force a call to {@link #doAttach} next time this file + * is used. + * + * @throws Exception if an error occurs. + */ + private void detach() throws Exception { + synchronized (fileSystem) { + if (attached) { + try { + doDetach(); + } finally { + attached = false; + setFileType(null); + parent = null; + + // fs.fileDetached(this); + + removeChildrenCache(); + // children = null; + } + } + } + } + + /** + * Attaches this file object to its file resource. + *

+ * This method is called before any of the doBlah() or onBlah() methods. Sub-classes can use this method to perform + * lazy initialization. + *

+ *

+ * This implementation does nothing. + *

+ * + * @throws Exception if an error occurs. + */ + protected void doAttach() throws Exception { + // noop + } + + /** + * Create a FileContent implementation. + * + * @return The FileContent. + * @throws FileSystemException if an error occurs. + * @since 2.0 + */ + protected FileContent doCreateFileContent() throws FileSystemException { + return new DefaultFileContent(this, getFileContentInfoFactory()); + } + + /** + * Creates this file as a folder. Is only called when: + *
    + *
  • {@link #doGetType} returns {@link FileType#IMAGINARY}.
  • + *
  • The parent folder exists and is writable, or this file is the root of the file system.
  • + *
+ * This implementation throws an exception. + * + * @throws Exception if an error occurs. + */ + protected void doCreateFolder() throws Exception { + throw new FileSystemException("vfs.provider/create-folder-not-supported.error"); + } + + /** + * Deletes the file. Is only called when: + *
    + *
  • {@link #doGetType} does not return {@link FileType#IMAGINARY}.
  • + *
  • {@link #doIsWriteable} returns true.
  • + *
  • This file has no children, if a folder.
  • + *
+ * This implementation throws an exception. + * + * @throws Exception if an error occurs. + */ + protected void doDelete() throws Exception { + throw new FileSystemException("vfs.provider/delete-not-supported.error"); + } + + /** + * Detaches this file object from its file resource. + *

+ * Called when this file is closed. Note that the file object may be reused later, so should be able to be + * reattached. + *

+ *

+ * This implementation does nothing. + *

+ * + * @throws Exception if an error occurs. + */ + protected void doDetach() throws Exception { + // noop + } + + /** + * Returns the attributes of this file. Is only called if {@link #doGetType} does not return + * {@link FileType#IMAGINARY}. + *

+ * This implementation always returns an empty map. + *

+ * + * @return The attributes of the file. + * @throws Exception if an error occurs. + */ + protected Map doGetAttributes() throws Exception { + return Collections.emptyMap(); + } + + /** + * Returns the certificates used to sign this file. Is only called if {@link #doGetType} does not return + * {@link FileType#IMAGINARY}. + *

+ * This implementation always returns null. + *

+ * + * @return The certificates used to sign the file. + * @throws Exception if an error occurs. + */ + protected Certificate[] doGetCertificates() throws Exception { + return null; + } + + /** + * Returns the size of the file content (in bytes). Is only called if {@link #doGetType} returns + * {@link FileType#FILE}. + * + * @return The size of the file in bytes. + * @throws Exception if an error occurs. + */ + protected abstract long doGetContentSize() throws Exception; + + /** + * Creates an input stream to read the file content from. Is only called if {@link #doGetType} returns + * {@link FileType#FILE}. + *

+ * It is guaranteed that there are no open output streams for this file when this method is called. + *

+ *

+ * The returned stream does not have to be buffered. + *

+ * + * @return An InputStream to read the file content. + * @throws Exception if an error occurs. + */ + protected InputStream doGetInputStream() throws Exception { + // Backward compatibility. + return doGetInputStream(DEFAULT_BUFFER_SIZE); + } + + /** + * Creates an input stream to read the file content from. Is only called if {@link #doGetType} returns + * {@link FileType#FILE}. + *

+ * It is guaranteed that there are no open output streams for this file when this method is called. + *

+ *

+ * The returned stream does not have to be buffered. + *

+ * @param bufferSize Buffer size hint. + * @return An InputStream to read the file content. + * @throws Exception if an error occurs. + */ + protected InputStream doGetInputStream(final int bufferSize) throws Exception { + throw new UnsupportedOperationException(DO_GET_INPUT_STREAM_INT); + } + + /** + * Returns the last modified time of this file. Is only called if {@link #doGetType} does not return + *

+ * This implementation throws an exception. + *

+ * + * @return The last modification time. + * @throws Exception if an error occurs. + */ + protected long doGetLastModifiedTime() throws Exception { + throw new FileSystemException("vfs.provider/get-last-modified-not-supported.error"); + } + + /** + * Creates an output stream to write the file content to. Is only called if: + *
    + *
  • {@link #doIsWriteable} returns true. + *
  • {@link #doGetType} returns {@link FileType#FILE}, or {@link #doGetType} returns {@link FileType#IMAGINARY}, + * and the file's parent exists and is a folder. + *
+ * It is guaranteed that there are no open stream (input or output) for this file when this method is called. + *

+ * The returned stream does not have to be buffered. + *

+ *

+ * This implementation throws an exception. + *

+ * + * @param bAppend true if the file should be appended to, false if it should be overwritten. + * @return An OutputStream to write to the file. + * @throws Exception if an error occurs. + */ + protected OutputStream doGetOutputStream(final boolean bAppend) throws Exception { + throw new FileSystemException("vfs.provider/write-not-supported.error"); + } + + /** + * Creates access to the file for random i/o. Is only called if {@link #doGetType} returns {@link FileType#FILE}. + *

+ * It is guaranteed that there are no open output streams for this file when this method is called. + *

+ * + * @param mode The mode to access the file. + * @return The RandomAccessContext. + * @throws Exception if an error occurs. + */ + protected RandomAccessContent doGetRandomAccessContent(final RandomAccessMode mode) throws Exception { + throw new FileSystemException("vfs.provider/random-access-not-supported.error"); + } + + /** + * Determines the type of this file. Must not return null. The return value of this method is cached, so the + * implementation can be expensive. + * + * @return the type of the file. + * @throws Exception if an error occurs. + */ + protected abstract FileType doGetType() throws Exception; + + /** + * Determines if this file is executable. Is only called if {@link #doGetType} does not return + * {@link FileType#IMAGINARY}. + *

+ * This implementation always returns false. + *

+ * + * @return true if the file is executable, false otherwise. + * @throws Exception if an error occurs. + */ + protected boolean doIsExecutable() throws Exception { + return false; + } + + /** + * Determines if this file is hidden. Is only called if {@link #doGetType} does not return + * {@link FileType#IMAGINARY}. + *

+ * This implementation always returns false. + *

+ * + * @return true if the file is hidden, false otherwise. + * @throws Exception if an error occurs. + */ + protected boolean doIsHidden() throws Exception { + return false; + } + + /** + * Determines if this file can be read. Is only called if {@link #doGetType} does not return + * {@link FileType#IMAGINARY}. + *

+ * This implementation always returns true. + *

+ * + * @return true if the file is readable, false otherwise. + * @throws Exception if an error occurs. + */ + protected boolean doIsReadable() throws Exception { + return true; + } + + /** + * Checks if this fileObject is the same file as {@code destFile} just with a different name. E.g. for + * case-insensitive file systems like Windows. + * + * @param destFile The file to compare to. + * @return true if the FileObjects are the same. + * @throws FileSystemException if an error occurs. + */ + protected boolean doIsSameFile(final FileObject destFile) throws FileSystemException { + return false; + } + + /** + * Determines if this file is a symbolic link. Is only called if {@link #doGetType} does not return + * {@link FileType#IMAGINARY}. + *

+ * This implementation always returns false. + *

+ * + * @return true if the file is readable, false otherwise. + * @throws Exception if an error occurs. + * @since 2.4 + */ + protected boolean doIsSymbolicLink() throws Exception { + return false; + } + + /** + * Determines if this file can be written to. Is only called if {@link #doGetType} does not return + * {@link FileType#IMAGINARY}. + *

+ * This implementation always returns true. + *

+ * + * @return true if the file is writable. + * @throws Exception if an error occurs. + */ + protected boolean doIsWriteable() throws Exception { + return true; + } + + /** + * Lists the children of this file. Is only called if {@link #doGetType} returns {@link FileType#FOLDER}. The return + * value of this method is cached, so the implementation can be expensive. + * + * @return a possible empty String array if the file is a directory or null or an exception if the file is not a + * directory or can't be read. + * @throws Exception if an error occurs. + */ + protected abstract String[] doListChildren() throws Exception; + + /** + * Lists the children of this file. + *

+ * Is only called if {@link #doGetType} returns {@link FileType#FOLDER}. + *

+ *

+ * The return value of this method is cached, so the implementation can be expensive. + * Other than {@code doListChildren} you could return FileObject's to e.g. reinitialize the type of the file. + *

+ *

+ * (Introduced for WebDAV: "permission denied on resource" during getType()) + *

+ * + * @return The children of this FileObject. + * @throws Exception if an error occurs. + */ + protected FileObject[] doListChildrenResolved() throws Exception { + return null; + } + + /** + * Removes an attribute of this file. + *

+ * Is only called if {@link #doGetType} does not return {@link FileType#IMAGINARY}. + *

+ *

+ * This implementation throws an exception. + *

+ * + * @param attrName The name of the attribute to remove. + * @throws Exception if an error occurs. + * @since 2.0 + */ + protected void doRemoveAttribute(final String attrName) throws Exception { + throw new FileSystemException("vfs.provider/remove-attribute-not-supported.error"); + } + + /** + * Renames the file. + *

+ * Is only called when: + *

+ *
    + *
  • {@link #doIsWriteable} returns true.
  • + *
+ *

+ * This implementation throws an exception. + *

+ * + * @param newFile A FileObject with the new file name. + * @throws Exception if an error occurs. + */ + protected void doRename(final FileObject newFile) throws Exception { + throw new FileSystemException("vfs.provider/rename-not-supported.error"); + } + + /** + * Sets an attribute of this file. + *

+ * Is only called if {@link #doGetType} does not return {@link FileType#IMAGINARY}. + *

+ *

+ * This implementation throws an exception. + *

+ * + * @param attrName The attribute name. + * @param value The value to be associated with the attribute name. + * @throws Exception if an error occurs. + */ + protected void doSetAttribute(final String attrName, final Object value) throws Exception { + throw new FileSystemException("vfs.provider/set-attribute-not-supported.error"); + } + + /** + * Make the file executable. + *

+ * Only called if {@link #doGetType} does not return {@link FileType#IMAGINARY}. + *

+ *

+ * This implementation returns false. + *

+ * + * @param executable True to allow access, false to disallow. + * @param ownerOnly If {@code true}, the permission applies only to the owner; otherwise, it applies to everybody. + * @return true if the operation succeeded. + * @throws Exception Any Exception thrown is wrapped in FileSystemException. + * @see #setExecutable(boolean, boolean) + * @since 2.1 + */ + protected boolean doSetExecutable(final boolean executable, final boolean ownerOnly) throws Exception { + return false; + } + + /** + * Sets the last modified time of this file. + *

+ * Is only called if {@link #doGetType} does not return {@link FileType#IMAGINARY}. + *

+ *

+ * This implementation throws an exception. + *

+ * + * @param modtime The last modification time. + * @return true if the time was set. + * @throws Exception Any Exception thrown is wrapped in FileSystemException. + */ + protected boolean doSetLastModifiedTime(final long modtime) throws Exception { + throw new FileSystemException("vfs.provider/set-last-modified-not-supported.error"); + } + + /** + * Make the file or folder readable. + *

+ * Only called if {@link #doGetType} does not return {@link FileType#IMAGINARY}. + *

+ *

+ * This implementation returns false. + *

+ * + * @param readable True to allow access, false to disallow + * @param ownerOnly If {@code true}, the permission applies only to the owner; otherwise, it applies to everybody. + * @return true if the operation succeeded + * @throws Exception Any Exception thrown is wrapped in FileSystemException. + * @see #setReadable(boolean, boolean) + * @since 2.1 + */ + protected boolean doSetReadable(final boolean readable, final boolean ownerOnly) throws Exception { + return false; + } + + /** + * Make the file or folder writable. + *

+ * Only called if {@link #doGetType} does not return {@link FileType#IMAGINARY}. + *

+ * + * @param writable True to allow access, false to disallow + * @param ownerOnly If {@code true}, the permission applies only to the owner; otherwise, it applies to everybody. + * @return true if the operation succeeded + * @throws Exception Any Exception thrown is wrapped in FileSystemException. + * @see #setWritable(boolean, boolean) + * @since 2.1 + */ + protected boolean doSetWritable(final boolean writable, final boolean ownerOnly) throws Exception { + return false; + } + + /** + * Called when the output stream for this file is closed. + * + * @throws Exception if an error occurs. + */ + protected void endOutput() throws Exception { + if (getType() == FileType.IMAGINARY) { + // File was created + handleCreate(FileType.FILE); + } else { + // File has changed + onChange(); + } + } + + /** + * Determines if the file exists. + * + * @return true if the file exists, false otherwise, + * @throws FileSystemException if an error occurs. + */ + @Override + public boolean exists() throws FileSystemException { + return getType() != FileType.IMAGINARY; + } + + private FileName[] extractNames(final FileObject[] objects) { + if (objects == null) { + return null; + } + return Stream.of(objects).filter(Objects::nonNull).map(FileObject::getName).toArray(FileName[]::new); + } + + @Override + protected void finalize() throws Throwable { + fileSystem.fileObjectDestroyed(this); + + super.finalize(); + } + + /** + * Finds the set of matching descendants of this file, in depthwise order. + * + * @param selector The FileSelector. + * @return list of files or null if the base file (this object) do not exist + * @throws FileSystemException if an error occurs. + */ + @Override + public FileObject[] findFiles(final FileSelector selector) throws FileSystemException { + final List list = this.listFiles(selector); + return list == null ? null : list.toArray(EMPTY_ARRAY); + } + + /** + * Traverses the descendants of this file, and builds a list of selected files. + * + * @param selector The FileSelector. + * @param depthwise if true files are added after their descendants, before otherwise. + * @param selected A List of the located FileObjects. + * @throws FileSystemException if an error occurs. + */ + @Override + public void findFiles(final FileSelector selector, final boolean depthwise, final List selected) + throws FileSystemException { + try { + if (exists()) { + // Traverse starting at this file + final DefaultFileSelectorInfo info = new DefaultFileSelectorInfo(); + info.setBaseFolder(this); + info.setDepth(0); + info.setFile(this); + traverse(info, selector, depthwise, selected); + } + } catch (final Exception e) { + throw new FileSystemException("vfs.provider/find-files.error", fileName, e); + } + } + + /** + * Returns the file system this file belongs to. + * + * @return The FileSystem this file is associated with. + */ + protected AFS getAbstractFileSystem() { + return fileSystem; + } + + /** + * Returns a child of this file. + * + * @param name The name of the child to locate. + * @return The FileObject for the file or null if the child does not exist. + * @throws FileSystemException if an error occurs. + */ + @Override + public FileObject getChild(final String name) throws FileSystemException { + // TODO - use a hashtable when there are a large number of children + final FileObject[] children = getChildren(); + for (final FileObject element : children) { + final FileName child = element.getName(); + final String childBaseName = child.getBaseName(); + // TODO - use a comparator to compare names + if (childBaseName.equals(name) || UriParser.decode(childBaseName).equals(name)) { + return resolveFile(child); + } + } + return null; + } + + /** + * Returns the children of the file. + * + * @return an array of FileObjects, one per child. + * @throws FileSystemException if an error occurs. + */ + @Override + public FileObject[] getChildren() throws FileSystemException { + synchronized (fileSystem) { + // VFS-210 + if (!fileSystem.hasCapability(Capability.LIST_CHILDREN)) { + throw new FileNotFolderException(fileName); + } + + /* + * VFS-210 if (!getType().hasChildren()) { throw new + * FileSystemException("vfs.provider/list-children-not-folder.error", name); } + */ + attach(); + + // Use cached info, if present + if (children != null) { + return resolveFiles(children); + } + + // allow the filesystem to return resolved children. e.g. prefill type for webdav + final FileObject[] childrenObjects; + try { + childrenObjects = doListChildrenResolved(); + children = extractNames(childrenObjects); + } catch (final FileSystemException exc) { + // VFS-210 + throw exc; + } catch (final Exception exc) { + throw new FileSystemException("vfs.provider/list-children.error", exc, fileName); + } + + if (childrenObjects != null) { + return childrenObjects; + } + + // List the children + final String[] files; + try { + files = doListChildren(); + } catch (final FileSystemException exc) { + // VFS-210 + throw exc; + } catch (final Exception exc) { + throw new FileSystemException("vfs.provider/list-children.error", exc, fileName); + } + + if (files == null) { + // VFS-210 + // honor the new doListChildren contract + // return null; + throw new FileNotFolderException(fileName); + } + if (files.length == 0) { + // No children + children = FileName.EMPTY_ARRAY; + } else { + // Create file objects for the children + final FileName[] cache = new FileName[files.length]; + for (int i = 0; i < files.length; i++) { + final String file = "./" + files[i]; // VFS-741: assume scheme prefix is file name only + cache[i] = fileSystem.getFileSystemManager().resolveName(fileName, file, NameScope.CHILD); + } + // VFS-285: only assign the children file names after all of them have been + // resolved successfully to prevent an inconsistent internal state + children = cache; + } + + return resolveFiles(children); + } + } + + /** + * Returns the file's content. + * + * @return the FileContent for this FileObject. + * @throws FileSystemException if an error occurs. + */ + @Override + public FileContent getContent() throws FileSystemException { + synchronized (fileSystem) { + attach(); + if (content == null) { + content = doCreateFileContent(); + } + return content; + } + } + + /** + * Creates the FileContentInfo factory. + * + * @return The FileContentInfoFactory. + */ + protected FileContentInfoFactory getFileContentInfoFactory() { + return fileSystem.getFileSystemManager().getFileContentInfoFactory(); + } + + /** + * @return FileOperations interface that provides access to the operations API. + * @throws FileSystemException if an error occurs. + */ + @Override + public FileOperations getFileOperations() throws FileSystemException { + if (operations == null) { + operations = new DefaultFileOperations(this); + } + + return operations; + } + + /** + * Returns the file system this file belongs to. + * + * @return The FileSystem this file is associated with. + */ + @Override + public FileSystem getFileSystem() { + return fileSystem; + } + + /** + * Returns an input stream to use to read the content of the file. + * + * @return The InputStream to access this file's content. + * @throws FileSystemException if an error occurs. + */ + public InputStream getInputStream() throws FileSystemException { + return getInputStream(DEFAULT_BUFFER_SIZE); + } + + /** + * Returns an input stream to use to read the content of the file. + * + * @param bufferSize buffer size hint. + * @return The InputStream to access this file's content. + * @throws FileSystemException if an error occurs. + */ + public InputStream getInputStream(final int bufferSize) throws FileSystemException { + // Get the raw input stream + try { + return doGetInputStream(bufferSize); + } catch (final org.apache.commons.vfs2.FileNotFoundException | FileNotFoundException exc) { + throw new org.apache.commons.vfs2.FileNotFoundException(fileName, exc); + } catch (final FileSystemException exc) { + throw exc; + } catch (final UnsupportedOperationException uoe) { + // TODO Remove for 3.0 + // Backward compatibility for subclasses before 2.5.0 + if (DO_GET_INPUT_STREAM_INT.equals(uoe.getMessage())) { + try { + // Invoke old API. + return doGetInputStream(); + } catch (final Exception e) { + if (e instanceof FileSystemException) { + throw (FileSystemException) e; + } + throw new FileSystemException("vfs.provider/read.error", fileName, e); + } + } + throw uoe; + } catch (final Exception exc) { + throw new FileSystemException("vfs.provider/read.error", fileName, exc); + } + } + + /** + * Returns the name of the file. + * + * @return The FileName, never {@code null}. + */ + @Override + public FileName getName() { + return fileName; + } + + // TODO: remove this method for the next major version as it is unused + /** + * Prepares this file for writing. Makes sure it is either a file, or its parent folder exists. Returns an output + * stream to use to write the content of the file to. + * + * @return An OutputStream where the new contents of the file can be written. + * @throws FileSystemException if an error occurs. + */ + public OutputStream getOutputStream() throws FileSystemException { + return getOutputStream(false); + } + + // TODO: mark this method as `final` and package-private for the next major version because + // it shouldn't be used from anywhere other than `DefaultFileContent` + /** + * Prepares this file for writing. Makes sure it is either a file, or its parent folder exists. Returns an output + * stream to use to write the content of the file to. + * + * @param bAppend true when append to the file. + * Note: If the underlying file system does not support appending, a FileSystemException is thrown. + * @return An OutputStream where the new contents of the file can be written. + * @throws FileSystemException if an error occurs; for example: + * bAppend is true, and the underlying FileSystem does not support it + */ + public OutputStream getOutputStream(final boolean bAppend) throws FileSystemException { + /* + * VFS-210 if (getType() != FileType.IMAGINARY && !getType().hasContent()) { throw new + * FileSystemException("vfs.provider/write-not-file.error", name); } if (!isWriteable()) { throw new + * FileSystemException("vfs.provider/write-read-only.error", name); } + */ + + if (bAppend && !fileSystem.hasCapability(Capability.APPEND_CONTENT)) { + throw new FileSystemException("vfs.provider/write-append-not-supported.error", fileName); + } + + if (getType() == FileType.IMAGINARY) { + // Does not exist - make sure parent does + final FileObject parent = getParent(); + if (parent != null) { + parent.createFolder(); + } + } + + // Get the raw output stream + try { + return doGetOutputStream(bAppend); + } catch (final RuntimeException re) { + throw re; + } catch (final Exception exc) { + throw new FileSystemException("vfs.provider/write.error", exc, fileName); + } + } + + /** + * Returns the parent of the file. + * + * @return the parent FileObject. + * @throws FileSystemException if an error occurs. + */ + @Override + public FileObject getParent() throws FileSystemException { + // equals is not implemented :-/ + if (this.compareTo(fileSystem.getRoot()) == 0) { + if (fileSystem.getParentLayer() == null) { + // Root file has no parent + return null; + } + // Return the parent of the parent layer + return fileSystem.getParentLayer().getParent(); + } + + synchronized (fileSystem) { + // Locate the parent of this file + if (parent == null) { + final FileName name = fileName.getParent(); + if (name == null) { + return null; + } + parent = fileSystem.resolveFile(name); + } + return parent; + } + } + + /** + * Returns the receiver as a URI String for public display, like, without a password. + * + * @return A URI String without a password, never {@code null}. + */ + @Override + public String getPublicURIString() { + return fileName.getFriendlyURI(); + } + + /** + * Returns an input/output stream to use to read and write the content of the file in and random manner. + * + * @param mode The RandomAccessMode. + * @return The RandomAccessContent. + * @throws FileSystemException if an error occurs. + */ + public RandomAccessContent getRandomAccessContent(final RandomAccessMode mode) throws FileSystemException { + // + // VFS-210 if (!getType().hasContent()) { throw new FileSystemException("vfs.provider/read-not-file.error", + // name); } + // + if (mode.requestRead()) { + if (!fileSystem.hasCapability(Capability.RANDOM_ACCESS_READ)) { + throw new FileSystemException("vfs.provider/random-access-read-not-supported.error"); + } + if (!isReadable()) { + throw new FileSystemException("vfs.provider/read-not-readable.error", fileName); + } + } + + if (mode.requestWrite()) { + if (!fileSystem.hasCapability(Capability.RANDOM_ACCESS_WRITE)) { + throw new FileSystemException("vfs.provider/random-access-write-not-supported.error"); + } + if (!isWriteable()) { + throw new FileSystemException("vfs.provider/write-read-only.error", fileName); + } + } + + // Get the raw input stream + try { + return doGetRandomAccessContent(mode); + } catch (final Exception exc) { + throw new FileSystemException("vfs.provider/random-access.error", fileName, exc); + } + } + + /** + * Returns the file's type. + * + * @return The FileType. + * @throws FileSystemException if an error occurs. + */ + @Override + public FileType getType() throws FileSystemException { + synchronized (fileSystem) { + attach(); + + // VFS-210: get the type only if requested for + try { + if (type == null) { + setFileType(doGetType()); + } + if (type == null) { + setFileType(FileType.IMAGINARY); + } + } catch (final Exception e) { + throw new FileSystemException("vfs.provider/get-type.error", e, fileName); + } + + return type; + } + } + + /** + * Returns a URL representation of the file. + * + * @return The URL representation of the file. + * @throws FileSystemException if an error occurs. + */ + @Override + public URL getURL() throws FileSystemException { + try { + return AccessController.doPrivileged((PrivilegedExceptionAction) () -> { + final StringBuilder buf = new StringBuilder(); + final String scheme = UriParser.extractScheme(fileSystem.getContext().getFileSystemManager().getSchemes(), fileName.getURI(), buf); + return new URL(scheme, "", -1, buf.toString(), + new DefaultURLStreamHandler(fileSystem.getContext(), fileSystem.getFileSystemOptions())); + }); + } catch (final PrivilegedActionException e) { + throw new FileSystemException("vfs.provider/get-url.error", fileName, e.getException()); + } + } + + /** + * Called when this file is changed. + *

+ * This will only happen if you monitor the file using {@link org.apache.commons.vfs2.FileMonitor}. + *

+ * + * @throws Exception if an error occurs. + */ + protected void handleChanged() throws Exception { + // Notify the file system + fileSystem.fireFileChanged(this); + } + + /** + * Called when this file is created. Updates cached info and notifies the parent and file system. + * + * @param newType The type of the file. + * @throws Exception if an error occurs. + */ + protected void handleCreate(final FileType newType) throws Exception { + synchronized (fileSystem) { + if (attached) { + // Fix up state + injectType(newType); + + removeChildrenCache(); + + // Notify subclass + onChange(); + } + + // Notify parent that its child list may no longer be valid + notifyParent(this.getName(), newType); + + // Notify the file system + fileSystem.fireFileCreated(this); + } + } + + /** + * Called when this file is deleted. Updates cached info and notifies subclasses, parent and file system. + * + * @throws Exception if an error occurs. + */ + protected void handleDelete() throws Exception { + synchronized (fileSystem) { + if (attached) { + // Fix up state + injectType(FileType.IMAGINARY); + removeChildrenCache(); + + // Notify subclass + onChange(); + } + + // Notify parent that its child list may no longer be valid + notifyParent(this.getName(), FileType.IMAGINARY); + + // Notify the file system + fileSystem.fireFileDeleted(this); + } + } + + /** + * This method is meant to add an object where this object holds a strong reference then. E.g. an archive-file system + * creates a list of all children and they shouldn't get garbage collected until the container is garbage collected + * + * @param strongRef The Object to add. + */ + // TODO should this be a FileObject? + public void holdObject(final Object strongRef) { + if (objects == null) { + objects = new ArrayList<>(INITIAL_LIST_SIZE); + } + objects.add(strongRef); + } + + /** + * Sets the file type. + * + * @param fileType the file type. + */ + protected void injectType(final FileType fileType) { + setFileType(fileType); + } + + /** + * Check if the internal state is "attached". + * + * @return true if this is the case + */ + @Override + public boolean isAttached() { + return attached; + } + + /** + * Check if the content stream is open. + * + * @return true if this is the case + */ + @Override + public boolean isContentOpen() { + if (content == null) { + return false; + } + + return content.isOpen(); + } + + /** + * Determines if this file is executable. + * + * @return {@code true} if this file is executable, {@code false} if not. + * @throws FileSystemException On error determining if this file exists. + */ + @Override + public boolean isExecutable() throws FileSystemException { + try { + return exists() && doIsExecutable(); + } catch (final Exception exc) { + throw new FileSystemException("vfs.provider/check-is-executable.error", fileName, exc); + } + } + + /** + * Checks if this file is a regular file by using its file type. + * + * @return true if this file is a regular file. + * @throws FileSystemException if an error occurs. + * @see #getType() + * @see FileType#FILE + */ + @Override + public boolean isFile() throws FileSystemException { + // Use equals instead of == to avoid any class loader worries. + return FileType.FILE.equals(this.getType()); + } + + /** + * Checks if this file is a folder by using its file type. + * + * @return true if this file is a regular file. + * @throws FileSystemException if an error occurs. + * @see #getType() + * @see FileType#FOLDER + */ + @Override + public boolean isFolder() throws FileSystemException { + // Use equals instead of == to avoid any class loader worries. + return FileType.FOLDER.equals(this.getType()); + } + + /** + * Determines if this file can be read. + * + * @return true if the file is a hidden file, false otherwise. + * @throws FileSystemException if an error occurs. + */ + @Override + public boolean isHidden() throws FileSystemException { + try { + return exists() && doIsHidden(); + } catch (final Exception exc) { + throw new FileSystemException("vfs.provider/check-is-hidden.error", fileName, exc); + } + } + + /** + * Determines if this file can be read. + * + * @return true if the file can be read, false otherwise. + * @throws FileSystemException if an error occurs. + */ + @Override + public boolean isReadable() throws FileSystemException { + try { + return exists() && doIsReadable(); + } catch (final Exception exc) { + throw new FileSystemException("vfs.provider/check-is-readable.error", fileName, exc); + } + } + + /** + * Checks if this fileObject is the same file as {@code destFile} just with a different name. E.g. for + * case-insensitive file systems like windows. + * + * @param destFile The file to compare to. + * @return true if the FileObjects are the same. + * @throws FileSystemException if an error occurs. + */ + protected boolean isSameFile(final FileObject destFile) throws FileSystemException { + attach(); + return doIsSameFile(destFile); + } + + /** + * Determines if this file can be read. + * + * @return true if the file can be read, false otherwise. + * @throws FileSystemException if an error occurs. + * @since 2.4 + */ + @Override + public boolean isSymbolicLink() throws FileSystemException { + try { + return exists() && doIsSymbolicLink(); + } catch (final Exception exc) { + throw new FileSystemException("vfs.provider/check-is-symbolic-link.error", fileName, exc); + } + } + + /** + * Determines if this file can be written to. + * + * @return true if the file can be written to, false otherwise. + * @throws FileSystemException if an error occurs. + */ + @Override + public boolean isWriteable() throws FileSystemException { + try { + if (exists()) { + return doIsWriteable(); + } + final FileObject parent = getParent(); + if (parent != null) { + return parent.isWriteable(); + } + return true; + } catch (final Exception exc) { + throw new FileSystemException("vfs.provider/check-is-writable.error", fileName, exc); + } + } + + /** + * Returns an iterator over a set of all FileObject in this file object. + * + * @return an Iterator. + */ + @Override + public Iterator iterator() { + try { + return listFiles(Selectors.SELECT_ALL).iterator(); + } catch (final FileSystemException e) { + throw new IllegalStateException(e); + } + } + + /** + * Lists the set of matching descendants of this file, in depthwise order. + * + * @param selector The FileSelector. + * @return list of files or null if the base file (this object) do not exist or the {@code selector} is null + * @throws FileSystemException if an error occurs. + */ + public List listFiles(final FileSelector selector) throws FileSystemException { + if (!exists() || selector == null) { + return null; + } + + final ArrayList list = new ArrayList<>(); + this.findFiles(selector, true, list); + return list; + } + + /** + * Moves (rename) the file to another one. + * + * @param destFile The target FileObject. + * @throws FileSystemException if an error occurs. + */ + @Override + public void moveTo(final FileObject destFile) throws FileSystemException { + if (canRenameTo(destFile)) { + if (!getParent().isWriteable()) { + throw new FileSystemException("vfs.provider/rename-parent-read-only.error", getName(), + getParent().getName()); + } + } else if (!isWriteable()) { + throw new FileSystemException("vfs.provider/rename-read-only.error", getName()); + } + + if (destFile.exists() && !isSameFile(destFile)) { + destFile.deleteAll(); + // throw new FileSystemException("vfs.provider/rename-dest-exists.error", destFile.getName()); + } + + if (canRenameTo(destFile)) { + // issue rename on same filesystem + try { + attach(); + // remember type to avoid attach + final FileType srcType = getType(); + + doRename(destFile); + + FileObjectUtils.getAbstractFileObject(destFile).handleCreate(srcType); + destFile.close(); // now the destFile is no longer imaginary. force reattach. + + handleDelete(); // fire delete-events. This file-object (src) is like deleted. + } catch (final RuntimeException re) { + throw re; + } catch (final Exception exc) { + throw new FileSystemException("vfs.provider/rename.error", exc, getName(), destFile.getName()); + } + } else { + // different fs - do the copy/delete stuff + + destFile.copyFrom(this, Selectors.SELECT_SELF); + + if ((destFile.getType().hasContent() + && destFile.getFileSystem().hasCapability(Capability.SET_LAST_MODIFIED_FILE) + || destFile.getType().hasChildren() + && destFile.getFileSystem().hasCapability(Capability.SET_LAST_MODIFIED_FOLDER)) + && fileSystem.hasCapability(Capability.GET_LAST_MODIFIED)) { + destFile.getContent().setLastModifiedTime(this.getContent().getLastModifiedTime()); + } + + deleteSelf(); + } + + } + + /** + * Called after this file-object closed all its streams. + */ + protected void notifyAllStreamsClosed() { + // noop + } + + /** + * Notify the parent of a change to its children, when a child is created or deleted. + * + * @param childName The name of the child. + * @param newType The type of the child. + * @throws Exception if an error occurs. + */ + private void notifyParent(final FileName childName, final FileType newType) throws Exception { + if (parent == null) { + final FileName parentName = fileName.getParent(); + if (parentName != null) { + // Locate the parent, if it is cached + parent = fileSystem.getFileFromCache(parentName); + } + } + + if (parent != null) { + FileObjectUtils.getAbstractFileObject(parent).childrenChanged(childName, newType); + } + } + + /** + * Called when the type or content of this file changes. + *

+ * This implementation does nothing. + *

+ * + * @throws Exception if an error occurs. + */ + protected void onChange() throws Exception { + // noop + } + + /** + * Called when the children of this file change. Allows subclasses to refresh any cached information about the + * children of this file. + *

+ * This implementation does nothing. + *

+ * + * @param child The name of the child that changed. + * @param newType The type of the file. + * @throws Exception if an error occurs. + */ + protected void onChildrenChanged(final FileName child, final FileType newType) throws Exception { + // noop + } + + /** + * This will prepare the fileObject to get resynchronized with the underlying file system if required. + * + * @throws FileSystemException if an error occurs. + */ + @Override + public void refresh() throws FileSystemException { + // Detach from the file + try { + detach(); + } catch (final Exception e) { + throw new FileSystemException("vfs.provider/resync.error", fileName, e); + } + } + + private void removeChildrenCache() { + children = null; + } + + private FileObject resolveFile(final FileName child) throws FileSystemException { + return fileSystem.resolveFile(child); + } + + /** + * Finds a file, relative to this file. + * + * @param path The path of the file to locate. Can either be a relative path, which is resolved relative to this + * file, or an absolute path, which is resolved relative to the file system that contains this file. + * @return The FileObject. + * @throws FileSystemException if an error occurs. + */ + @Override + public FileObject resolveFile(final String path) throws FileSystemException { + final FileName otherName = fileSystem.getFileSystemManager().resolveName(fileName, path); + return fileSystem.resolveFile(otherName); + } + + /** + * Returns a child by name. + * + * @param name The name of the child to locate. + * @param scope the NameScope. + * @return The FileObject for the file or null if the child does not exist. + * @throws FileSystemException if an error occurs. + */ + @Override + public FileObject resolveFile(final String name, final NameScope scope) throws FileSystemException { + // return fs.resolveFile(this.name.resolveName(name, scope)); + return fileSystem.resolveFile(fileSystem.getFileSystemManager().resolveName(fileName, name, scope)); + } + + private FileObject[] resolveFiles(final FileName[] children) throws FileSystemException { + if (children == null) { + return null; + } + + final FileObject[] objects = new FileObject[children.length]; + for (int iterChildren = 0; iterChildren < children.length; iterChildren++) { + objects[iterChildren] = resolveFile(children[iterChildren]); + } + + return objects; + } + + @Override + public boolean setExecutable(final boolean readable, final boolean ownerOnly) throws FileSystemException { + try { + return exists() && doSetExecutable(readable, ownerOnly); + } catch (final Exception exc) { + throw new FileSystemException("vfs.provider/set-executable.error", fileName, exc); + } + } + + private void setFileType(final FileType type) { + if (type != null && type != FileType.IMAGINARY) { + Uncheck.run(() -> fileName.setType(type)); + } + this.type = type; + } + + @Override + public boolean setReadable(final boolean readable, final boolean ownerOnly) throws FileSystemException { + try { + return exists() && doSetReadable(readable, ownerOnly); + } catch (final Exception exc) { + throw new FileSystemException("vfs.provider/set-readable.error", fileName, exc); + } + } + + @Override + public boolean setWritable(final boolean readable, final boolean ownerOnly) throws FileSystemException { + try { + return exists() && doSetWritable(readable, ownerOnly); + } catch (final Exception exc) { + throw new FileSystemException("vfs.provider/set-writable.error", fileName, exc); + } + } + + /** + * Returns the URI as a String. + * + * @return Returns the URI as a String. + */ + @Override + public String toString() { + return fileName.getURI(); + } +} diff --git a/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/DelegateFileObject.java b/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/DelegateFileObject.java index 07a754bacd..c4174af302 100644 --- a/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/DelegateFileObject.java +++ b/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/DelegateFileObject.java @@ -1,424 +1,424 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.vfs2.provider; - -import java.io.InputStream; -import java.io.OutputStream; -import java.security.cert.Certificate; -import java.util.HashSet; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.stream.Stream; - -import org.apache.commons.lang3.ArrayUtils; -import org.apache.commons.vfs2.FileChangeEvent; -import org.apache.commons.vfs2.FileContent; -import org.apache.commons.vfs2.FileContentInfo; -import org.apache.commons.vfs2.FileListener; -import org.apache.commons.vfs2.FileName; -import org.apache.commons.vfs2.FileNotFolderException; -import org.apache.commons.vfs2.FileObject; -import org.apache.commons.vfs2.FileSystemException; -import org.apache.commons.vfs2.FileType; -import org.apache.commons.vfs2.RandomAccessContent; -import org.apache.commons.vfs2.util.RandomAccessMode; -import org.apache.commons.vfs2.util.WeakRefFileListener; - -/** - * A file backed by another file. - *

- * TODO - Extract subclass that overlays the children. - *

- * - * @param A subclass of AbstractFileSystem. - */ -public class DelegateFileObject extends AbstractFileObject implements FileListener { - - private FileObject fileObject; - private final Set children = new HashSet<>(); - private boolean ignoreEvent; - - /** - * Constructs a new instance. - * - * @param fileName the file name. - * @param fileSystem the file system. - * @param fileObject My file object. - * @throws FileSystemException For subclasses to throw. - */ - public DelegateFileObject(final AbstractFileName fileName, final AFS fileSystem, final FileObject fileObject) throws FileSystemException { - super(fileName, fileSystem); - this.fileObject = fileObject; - if (fileObject != null) { - WeakRefFileListener.installListener(fileObject, this); - } - } - - /** - * Adds a child to this file. - * - * @param baseName The base FileName. - * @param type The FileType. - * @throws Exception if an error occurs. - */ - public void attachChild(final FileName baseName, final FileType type) throws Exception { - final FileType oldType = doGetType(); - if (children.add(baseName.getBaseName())) { - childrenChanged(baseName, type); - } - maybeTypeChanged(oldType); - } - - /** - * Close the delegated file. - * - * @throws FileSystemException if an error occurs. - */ - @Override - public void close() throws FileSystemException { - super.close(); - - if (fileObject != null) { - fileObject.close(); - } - } - - /** - * Creates this file as a folder. - */ - @Override - protected void doCreateFolder() throws Exception { - ignoreEvent = true; - try { - fileObject.createFolder(); - } finally { - ignoreEvent = false; - } - } - - /** - * Deletes the file. - */ - @Override - protected void doDelete() throws Exception { - ignoreEvent = true; - try { - fileObject.delete(); - } finally { - ignoreEvent = false; - } - } - - /** - * Returns the attributes of this file. - */ - @Override - protected Map doGetAttributes() throws Exception { - return getFileContent().getAttributes(); - } - - /** - * Returns the certificates of this file. - */ - @Override - protected Certificate[] doGetCertificates() throws Exception { - return getFileContent().getCertificates(); - } - - /** - * Gets file content info. - * - * @return the file content info of the delegee. - * @throws Exception Any thrown Exception is wrapped in FileSystemException. - * @since 2.0 - */ - protected FileContentInfo doGetContentInfo() throws Exception { - return getFileContent().getContentInfo(); - } - - /** - * Returns the size of the file content (in bytes). Is only called if {@link #doGetType} returns - * {@link FileType#FILE}. - */ - @Override - protected long doGetContentSize() throws Exception { - return getFileContent().getSize(); - } - - /** - * Creates an input stream to read the file content from. - */ - @Override - protected InputStream doGetInputStream(final int bufferSize) throws Exception { - return getFileContent().getInputStream(bufferSize); - } - - /** - * Returns the last-modified time of this file. - */ - @Override - protected long doGetLastModifiedTime() throws Exception { - return getFileContent().getLastModifiedTime(); - } - - /** - * Creates an output stream to write the file content to. - */ - @Override - protected OutputStream doGetOutputStream(final boolean bAppend) throws Exception { - return getFileContent().getOutputStream(bAppend); - } - - /** - * Creates access to the file for random I/O. - * - * @since 2.0 - */ - @Override - protected RandomAccessContent doGetRandomAccessContent(final RandomAccessMode mode) throws Exception { - return getFileContent().getRandomAccessContent(mode); - } - - /** - * Determines the type of the file, returns null if the file does not exist. - */ - @Override - protected FileType doGetType() throws FileSystemException { - if (fileObject != null) { - return fileObject.getType(); - } - if (children.isEmpty()) { - return FileType.IMAGINARY; - } - return FileType.FOLDER; - } - - /** - * Determines if this file is executable. - */ - @Override - protected boolean doIsExecutable() throws FileSystemException { - if (fileObject != null) { - return fileObject.isExecutable(); - } - return false; - } - - /** - * Determines if this file is hidden. - */ - @Override - protected boolean doIsHidden() throws FileSystemException { - if (fileObject != null) { - return fileObject.isHidden(); - } - return false; - } - - /** - * Determines if this file can be read. - */ - @Override - protected boolean doIsReadable() throws FileSystemException { - if (fileObject != null) { - return fileObject.isReadable(); - } - return true; - } - - /** - * Determines if this file can be written to. - */ - @Override - protected boolean doIsWriteable() throws FileSystemException { - if (fileObject != null) { - return fileObject.isWriteable(); - } - return false; - } - - /** - * Lists the children of the file. - */ - @Override - protected String[] doListChildren() throws Exception { - if (fileObject != null) { - final FileObject[] children; - - try { - children = fileObject.getChildren(); - } catch (final FileNotFolderException e) { - // VFS-210 - throw new FileNotFolderException(getName(), e); - } - - return Stream.of(children).filter(Objects::nonNull).map(child -> child.getName().getBaseName()).toArray(String[]::new); - } - return children.toArray(ArrayUtils.EMPTY_STRING_ARRAY); - } - - /** - * Removes an attribute of this file. - * - * @since 2.0 - */ - @Override - protected void doRemoveAttribute(final String attrName) throws Exception { - getFileContent().removeAttribute(attrName); - } - - /** - * Renames the file. - * - * @param newFile the new location/name. - * @throws Exception Any thrown Exception is wrapped in FileSystemException. - * @since 2.0 - */ - @Override - protected void doRename(final FileObject newFile) throws Exception { - fileObject.moveTo(((DelegateFileObject) newFile).fileObject); - } - - /** - * Sets an attribute of this file. - */ - @Override - protected void doSetAttribute(final String attrName, final Object value) throws Exception { - getFileContent().setAttribute(attrName, value); - } - - /** - * Sets the last-modified time of this file. - * - * @since 2.0 - */ - @Override - protected boolean doSetLastModifiedTime(final long modtime) throws Exception { - getFileContent().setLastModifiedTime(modtime); - return true; - } - - /** - * Called when a file is changed. - *

- * This will only happen if you monitor the file using {@link org.apache.commons.vfs2.FileMonitor}. - *

- * - * @param event The FileChangeEvent. - * @throws Exception if an error occurs. - */ - @Override - public void fileChanged(final FileChangeEvent event) throws Exception { - if (event.getFileObject() != fileObject) { - return; - } - if (!ignoreEvent) { - handleChanged(); - } - } - - /** - * Called when a file is created. - * - * @param event The FileChangeEvent. - * @throws Exception if an error occurs. - */ - @Override - public void fileCreated(final FileChangeEvent event) throws Exception { - if (event.getFileObject() != fileObject) { - return; - } - if (!ignoreEvent) { - handleCreate(fileObject.getType()); - } - } - - /** - * Called when a file is deleted. - * - * @param event The FileChangeEvent. - * @throws Exception if an error occurs. - */ - @Override - public void fileDeleted(final FileChangeEvent event) throws Exception { - if (event.getFileObject() != fileObject) { - return; - } - if (!ignoreEvent) { - handleDelete(); - } - } - - /** - * Gets access to the delegated file. - * - * @return The FileObject. - * @since 2.0 - */ - public FileObject getDelegateFile() { - return fileObject; - } - - FileContent getFileContent() throws FileSystemException { - return fileObject.getContent(); - } - - /** - * Checks whether the file's type has changed, and fires the appropriate events. - * - * @param oldType The old FileType. - * @throws Exception if an error occurs. - */ - private void maybeTypeChanged(final FileType oldType) throws Exception { - final FileType newType = doGetType(); - if (oldType == FileType.IMAGINARY && newType != FileType.IMAGINARY) { - handleCreate(newType); - } else if (oldType != FileType.IMAGINARY && newType == FileType.IMAGINARY) { - handleDelete(); - } - } - - /** - * Refresh file information. - * - * @throws FileSystemException if an error occurs. - * @since 2.0 - */ - @Override - public void refresh() throws FileSystemException { - super.refresh(); - if (fileObject != null) { - fileObject.refresh(); - } - } - - /** - * Attaches or detaches the target file. - * - * @param fileObject The FileObject. - * @throws Exception if an error occurs. - */ - public void setFile(final FileObject fileObject) throws Exception { - final FileType oldType = doGetType(); - if (fileObject != null) { - WeakRefFileListener.installListener(fileObject, this); - } - this.fileObject = fileObject; - maybeTypeChanged(oldType); - } -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.vfs2.provider; + +import java.io.InputStream; +import java.io.OutputStream; +import java.security.cert.Certificate; +import java.util.HashSet; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Stream; + +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.vfs2.FileChangeEvent; +import org.apache.commons.vfs2.FileContent; +import org.apache.commons.vfs2.FileContentInfo; +import org.apache.commons.vfs2.FileListener; +import org.apache.commons.vfs2.FileName; +import org.apache.commons.vfs2.FileNotFolderException; +import org.apache.commons.vfs2.FileObject; +import org.apache.commons.vfs2.FileSystemException; +import org.apache.commons.vfs2.FileType; +import org.apache.commons.vfs2.RandomAccessContent; +import org.apache.commons.vfs2.util.RandomAccessMode; +import org.apache.commons.vfs2.util.WeakRefFileListener; + +/** + * A file backed by another file. + *

+ * TODO - Extract subclass that overlays the children. + *

+ * + * @param A subclass of AbstractFileSystem. + */ +public class DelegateFileObject extends AbstractFileObject implements FileListener { + + private FileObject fileObject; + private final Set children = new HashSet<>(); + private boolean ignoreEvent; + + /** + * Constructs a new instance. + * + * @param fileName the file name. + * @param fileSystem the file system. + * @param fileObject My file object. + * @throws FileSystemException For subclasses to throw. + */ + public DelegateFileObject(final AbstractFileName fileName, final AFS fileSystem, final FileObject fileObject) throws FileSystemException { + super(fileName, fileSystem); + this.fileObject = fileObject; + if (fileObject != null) { + WeakRefFileListener.installListener(fileObject, this); + } + } + + /** + * Adds a child to this file. + * + * @param baseName The base FileName. + * @param type The FileType. + * @throws Exception if an error occurs. + */ + public void attachChild(final FileName baseName, final FileType type) throws Exception { + final FileType oldType = doGetType(); + if (children.add(baseName.getBaseName())) { + childrenChanged(baseName, type); + } + maybeTypeChanged(oldType); + } + + /** + * Close the delegated file. + * + * @throws FileSystemException if an error occurs. + */ + @Override + public void close() throws FileSystemException { + super.close(); + + if (fileObject != null) { + fileObject.close(); + } + } + + /** + * Creates this file as a folder. + */ + @Override + protected void doCreateFolder() throws Exception { + ignoreEvent = true; + try { + fileObject.createFolder(); + } finally { + ignoreEvent = false; + } + } + + /** + * Deletes the file. + */ + @Override + protected void doDelete() throws Exception { + ignoreEvent = true; + try { + fileObject.delete(); + } finally { + ignoreEvent = false; + } + } + + /** + * Returns the attributes of this file. + */ + @Override + protected Map doGetAttributes() throws Exception { + return getFileContent().getAttributes(); + } + + /** + * Returns the certificates of this file. + */ + @Override + protected Certificate[] doGetCertificates() throws Exception { + return getFileContent().getCertificates(); + } + + /** + * Gets file content info. + * + * @return the file content info of the delegee. + * @throws Exception Any thrown Exception is wrapped in FileSystemException. + * @since 2.0 + */ + protected FileContentInfo doGetContentInfo() throws Exception { + return getFileContent().getContentInfo(); + } + + /** + * Returns the size of the file content (in bytes). Is only called if {@link #doGetType} returns + * {@link FileType#FILE}. + */ + @Override + protected long doGetContentSize() throws Exception { + return getFileContent().getSize(); + } + + /** + * Creates an input stream to read the file content from. + */ + @Override + protected InputStream doGetInputStream(final int bufferSize) throws Exception { + return getFileContent().getInputStream(bufferSize); + } + + /** + * Returns the last-modified time of this file. + */ + @Override + protected long doGetLastModifiedTime() throws Exception { + return getFileContent().getLastModifiedTime(); + } + + /** + * Creates an output stream to write the file content to. + */ + @Override + protected OutputStream doGetOutputStream(final boolean bAppend) throws Exception { + return getFileContent().getOutputStream(bAppend); + } + + /** + * Creates access to the file for random I/O. + * + * @since 2.0 + */ + @Override + protected RandomAccessContent doGetRandomAccessContent(final RandomAccessMode mode) throws Exception { + return getFileContent().getRandomAccessContent(mode); + } + + /** + * Determines the type of the file, returns null if the file does not exist. + */ + @Override + protected FileType doGetType() throws FileSystemException { + if (fileObject != null) { + return fileObject.getType(); + } + if (children.isEmpty()) { + return FileType.IMAGINARY; + } + return FileType.FOLDER; + } + + /** + * Determines if this file is executable. + */ + @Override + protected boolean doIsExecutable() throws FileSystemException { + if (fileObject != null) { + return fileObject.isExecutable(); + } + return false; + } + + /** + * Determines if this file is hidden. + */ + @Override + protected boolean doIsHidden() throws FileSystemException { + if (fileObject != null) { + return fileObject.isHidden(); + } + return false; + } + + /** + * Determines if this file can be read. + */ + @Override + protected boolean doIsReadable() throws FileSystemException { + if (fileObject != null) { + return fileObject.isReadable(); + } + return true; + } + + /** + * Determines if this file can be written to. + */ + @Override + protected boolean doIsWriteable() throws FileSystemException { + if (fileObject != null) { + return fileObject.isWriteable(); + } + return false; + } + + /** + * Lists the children of the file. + */ + @Override + protected String[] doListChildren() throws Exception { + if (fileObject != null) { + final FileObject[] children; + + try { + children = fileObject.getChildren(); + } catch (final FileNotFolderException e) { + // VFS-210 + throw new FileNotFolderException(getName(), e); + } + + return Stream.of(children).filter(Objects::nonNull).map(child -> child.getName().getBaseName()).toArray(String[]::new); + } + return children.toArray(ArrayUtils.EMPTY_STRING_ARRAY); + } + + /** + * Removes an attribute of this file. + * + * @since 2.0 + */ + @Override + protected void doRemoveAttribute(final String attrName) throws Exception { + getFileContent().removeAttribute(attrName); + } + + /** + * Renames the file. + * + * @param newFile the new location/name. + * @throws Exception Any thrown Exception is wrapped in FileSystemException. + * @since 2.0 + */ + @Override + protected void doRename(final FileObject newFile) throws Exception { + fileObject.moveTo(((DelegateFileObject) newFile).fileObject); + } + + /** + * Sets an attribute of this file. + */ + @Override + protected void doSetAttribute(final String attrName, final Object value) throws Exception { + getFileContent().setAttribute(attrName, value); + } + + /** + * Sets the last-modified time of this file. + * + * @since 2.0 + */ + @Override + protected boolean doSetLastModifiedTime(final long modtime) throws Exception { + getFileContent().setLastModifiedTime(modtime); + return true; + } + + /** + * Called when a file is changed. + *

+ * This will only happen if you monitor the file using {@link org.apache.commons.vfs2.FileMonitor}. + *

+ * + * @param event The FileChangeEvent. + * @throws Exception if an error occurs. + */ + @Override + public void fileChanged(final FileChangeEvent event) throws Exception { + if (event.getFileObject() != fileObject) { + return; + } + if (!ignoreEvent) { + handleChanged(); + } + } + + /** + * Called when a file is created. + * + * @param event The FileChangeEvent. + * @throws Exception if an error occurs. + */ + @Override + public void fileCreated(final FileChangeEvent event) throws Exception { + if (event.getFileObject() != fileObject) { + return; + } + if (!ignoreEvent) { + handleCreate(fileObject.getType()); + } + } + + /** + * Called when a file is deleted. + * + * @param event The FileChangeEvent. + * @throws Exception if an error occurs. + */ + @Override + public void fileDeleted(final FileChangeEvent event) throws Exception { + if (event.getFileObject() != fileObject) { + return; + } + if (!ignoreEvent) { + handleDelete(); + } + } + + /** + * Gets access to the delegated file. + * + * @return The FileObject. + * @since 2.0 + */ + public FileObject getDelegateFile() { + return fileObject; + } + + FileContent getFileContent() throws FileSystemException { + return fileObject.getContent(); + } + + /** + * Checks whether the file's type has changed, and fires the appropriate events. + * + * @param oldType The old FileType. + * @throws Exception if an error occurs. + */ + private void maybeTypeChanged(final FileType oldType) throws Exception { + final FileType newType = doGetType(); + if (oldType == FileType.IMAGINARY && newType != FileType.IMAGINARY) { + handleCreate(newType); + } else if (oldType != FileType.IMAGINARY && newType == FileType.IMAGINARY) { + handleDelete(); + } + } + + /** + * Refresh file information. + * + * @throws FileSystemException if an error occurs. + * @since 2.0 + */ + @Override + public void refresh() throws FileSystemException { + super.refresh(); + if (fileObject != null) { + fileObject.refresh(); + } + } + + /** + * Attaches or detaches the target file. + * + * @param fileObject The FileObject. + * @throws Exception if an error occurs. + */ + public void setFile(final FileObject fileObject) throws Exception { + final FileType oldType = doGetType(); + if (fileObject != null) { + WeakRefFileListener.installListener(fileObject, this); + } + this.fileObject = fileObject; + maybeTypeChanged(oldType); + } +} diff --git a/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/LayeredFileNameParser.java b/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/LayeredFileNameParser.java index d3fcda9f68..a4b737bc1a 100644 --- a/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/LayeredFileNameParser.java +++ b/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/LayeredFileNameParser.java @@ -1,124 +1,124 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.vfs2.provider; - -import org.apache.commons.vfs2.FileName; -import org.apache.commons.vfs2.FileSystemException; -import org.apache.commons.vfs2.FileType; - -/** - * Implementation for layered file systems. - *

- * Additionally encodes the '!' character. - *

- */ -public class LayeredFileNameParser extends AbstractFileNameParser { - - private static final LayeredFileNameParser INSTANCE = new LayeredFileNameParser(); - - /** - * Gets the singleton instance. - * - * @return the singleton instance. - */ - public static LayeredFileNameParser getInstance() { - return INSTANCE; - } - - /** - * Constructs a new instance. - */ - public LayeredFileNameParser() { - // empty - } - - /** - * Determines if a character should be encoded. - * - * @param ch The character to check. - * @return true if the character should be encoded. - */ - @Override - public boolean encodeCharacter(final char ch) { - return super.encodeCharacter(ch) || ch == LayeredFileName.LAYER_SEPARATOR; - } - - /** - * Pops the root prefix off a URI, which has had the scheme removed. - * - * @param uri string builder which gets modified. - * @return the extracted root name. - */ - protected String extractRootName(final StringBuilder uri) { - // Looking for ! (staring at the end) - final int maxlen = uri.length(); - int pos = maxlen - 1; - while (pos > 0 && uri.charAt(pos) != LayeredFileName.LAYER_SEPARATOR) { - pos--; - } - - if (pos == 0 && uri.charAt(pos) != LayeredFileName.LAYER_SEPARATOR) { - // not ! found, so take the whole path a root - // e.g. zip:/my/zip/file.zip - pos = maxlen; - } - - // Extract the name - final String prefix = uri.substring(0, pos); - if (pos < maxlen) { - uri.delete(0, pos + 1); - } else { - uri.setLength(0); - } - - return prefix; - } - - /** - * Parses the base and name into a FileName. - * - * @param context The component context. - * @param baseFileName The base FileName. - * @param fileName name The target file name. - * @return The constructed FileName. - * @throws FileSystemException if an error occurs. - */ - @Override - public FileName parseUri(final VfsComponentContext context, final FileName baseFileName, final String fileName) - throws FileSystemException { - final StringBuilder name = new StringBuilder(); - - // Extract the scheme - final String scheme = UriParser.extractScheme(context.getFileSystemManager().getSchemes(), fileName, name); - - // Extract the Layered file URI - final String rootUriName = extractRootName(name); - FileName rootUri = null; - if (rootUriName != null) { - rootUri = context.parseURI(rootUriName); - } - - // Decode and normalise the path - UriParser.canonicalizePath(name, 0, name.length(), this); - UriParser.fixSeparators(name); - final FileType fileType = UriParser.normalisePath(name); - final String path = name.toString(); - - return new LayeredFileName(scheme, rootUri, path, fileType); - } - -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.vfs2.provider; + +import org.apache.commons.vfs2.FileName; +import org.apache.commons.vfs2.FileSystemException; +import org.apache.commons.vfs2.FileType; + +/** + * Implementation for layered file systems. + *

+ * Additionally encodes the '!' character. + *

+ */ +public class LayeredFileNameParser extends AbstractFileNameParser { + + private static final LayeredFileNameParser INSTANCE = new LayeredFileNameParser(); + + /** + * Gets the singleton instance. + * + * @return the singleton instance. + */ + public static LayeredFileNameParser getInstance() { + return INSTANCE; + } + + /** + * Constructs a new instance. + */ + public LayeredFileNameParser() { + // empty + } + + /** + * Determines if a character should be encoded. + * + * @param ch The character to check. + * @return true if the character should be encoded. + */ + @Override + public boolean encodeCharacter(final char ch) { + return super.encodeCharacter(ch) || ch == LayeredFileName.LAYER_SEPARATOR; + } + + /** + * Pops the root prefix off a URI, which has had the scheme removed. + * + * @param uri string builder which gets modified. + * @return the extracted root name. + */ + protected String extractRootName(final StringBuilder uri) { + // Looking for ! (staring at the end) + final int maxlen = uri.length(); + int pos = maxlen - 1; + while (pos > 0 && uri.charAt(pos) != LayeredFileName.LAYER_SEPARATOR) { + pos--; + } + + if (pos == 0 && uri.charAt(pos) != LayeredFileName.LAYER_SEPARATOR) { + // not ! found, so take the whole path a root + // e.g. zip:/my/zip/file.zip + pos = maxlen; + } + + // Extract the name + final String prefix = uri.substring(0, pos); + if (pos < maxlen) { + uri.delete(0, pos + 1); + } else { + uri.setLength(0); + } + + return prefix; + } + + /** + * Parses the base and name into a FileName. + * + * @param context The component context. + * @param baseFileName The base FileName. + * @param fileName name The target file name. + * @return The constructed FileName. + * @throws FileSystemException if an error occurs. + */ + @Override + public FileName parseUri(final VfsComponentContext context, final FileName baseFileName, final String fileName) + throws FileSystemException { + final StringBuilder name = new StringBuilder(); + + // Extract the scheme + final String scheme = UriParser.extractScheme(context.getFileSystemManager().getSchemes(), fileName, name); + + // Extract the Layered file URI + final String rootUriName = extractRootName(name); + FileName rootUri = null; + if (rootUriName != null) { + rootUri = context.parseURI(rootUriName); + } + + // Decode and normalise the path + UriParser.canonicalizePath(name, 0, name.length(), this); + UriParser.fixSeparators(name); + final FileType fileType = UriParser.normalisePath(name); + final String path = name.toString(); + + return new LayeredFileName(scheme, rootUri, path, fileType); + } + +} diff --git a/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/UriParser.java b/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/UriParser.java index 2c65ad5422..b50a6a4f44 100644 --- a/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/UriParser.java +++ b/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/UriParser.java @@ -1,575 +1,575 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.vfs2.provider; - -import java.util.Arrays; - -import org.apache.commons.lang3.SystemUtils; -import org.apache.commons.vfs2.FileName; -import org.apache.commons.vfs2.FileSystemException; -import org.apache.commons.vfs2.FileType; -import org.apache.commons.vfs2.VFS; - -/** - * Utilities for dealing with URIs. See RFC 2396 for details. - */ -public final class UriParser { - - /** - * The set of valid separators. These are all converted to the normalized one. Does not contain the - * normalized separator - */ - // public static final char[] separators = {'\\'}; - public static final char TRANS_SEPARATOR = '\\'; - - /** - * The normalised separator to use. - */ - private static final char SEPARATOR_CHAR = FileName.SEPARATOR_CHAR; - - private static final int HEX_BASE = 16; - - private static final int BITS_IN_HALF_BYTE = 4; - - private static final char LOW_MASK = 0x0F; - - /** - * Encodes and appends a string to a StringBuilder. - * - * @param buffer The StringBuilder to append to. - * @param unencodedValue The String to encode and append. - * @param reserved characters to encode. - */ - public static void appendEncoded(final StringBuilder buffer, final String unencodedValue, final char[] reserved) { - final int offset = buffer.length(); - buffer.append(unencodedValue); - encode(buffer, offset, unencodedValue.length(), reserved); - } - - static void appendEncodedRfc2396(final StringBuilder buffer, final String unencodedValue, final char[] allowed) { - final int offset = buffer.length(); - buffer.append(unencodedValue); - encodeRfc2396(buffer, offset, unencodedValue.length(), allowed); - } - - /** - * Canonicalizes a path. - * - * @param buffer Source data. - * @param offset Where to start reading. - * @param length How much to read. - * @param fileNameParser Now to encode and decode. - * @throws FileSystemException If an I/O error occurs. - */ - public static void canonicalizePath(final StringBuilder buffer, final int offset, final int length, - final FileNameParser fileNameParser) throws FileSystemException { - int index = offset; - int count = length; - for (; count > 0; count--, index++) { - final char ch = buffer.charAt(index); - if (ch == '%') { - if (count < 3) { - throw new FileSystemException("vfs.provider/invalid-escape-sequence.error", - buffer.substring(index, index + count)); - } - - // Decode - final int dig1 = Character.digit(buffer.charAt(index + 1), HEX_BASE); - final int dig2 = Character.digit(buffer.charAt(index + 2), HEX_BASE); - if (dig1 == -1 || dig2 == -1) { - throw new FileSystemException("vfs.provider/invalid-escape-sequence.error", - buffer.substring(index, index + 3)); - } - final char value = (char) (dig1 << BITS_IN_HALF_BYTE | dig2); - - final boolean match = value == '%' || fileNameParser.encodeCharacter(value); - - if (match) { - // this is a reserved character, not allowed to decode - index += 2; - count -= 2; - continue; - } - - // Replace - buffer.setCharAt(index, value); - buffer.delete(index + 1, index + 3); - count -= 2; - } else if (fileNameParser.encodeCharacter(ch)) { - // Encode - final char[] digits = {Character.forDigit(ch >> BITS_IN_HALF_BYTE & LOW_MASK, HEX_BASE), Character.forDigit(ch & LOW_MASK, HEX_BASE)}; - buffer.setCharAt(index, '%'); - buffer.insert(index + 1, digits); - index += 2; - } - } - } - - /** - * Decodes the String. - * - * @param uri The String to decode. - * @throws FileSystemException if an error occurs. - */ - public static void checkUriEncoding(final String uri) throws FileSystemException { - decode(uri); - } - - /** - * Removes %nn encodings from a string. - * - * @param encodedStr The encoded String. - * @return The decoded String. - * @throws FileSystemException if an error occurs. - */ - public static String decode(final String encodedStr) throws FileSystemException { - if (encodedStr == null) { - return null; - } - if (encodedStr.indexOf('%') < 0) { - return encodedStr; - } - final StringBuilder buffer = new StringBuilder(encodedStr); - decode(buffer, 0, buffer.length()); - return buffer.toString(); - } - - /** - * Removes %nn encodings from a string. - * - * @param buffer StringBuilder containing the string to decode. - * @param offset The position in the string to start decoding. - * @param length The number of characters to decode. - * @throws FileSystemException if an error occurs. - */ - public static void decode(final StringBuilder buffer, final int offset, final int length) - throws FileSystemException { - int index = offset; - int count = length; - boolean ipv6Host = false; - for (; count > 0; count--, index++) { - final char ch = buffer.charAt(index); - if (ch == '[') { - ipv6Host = true; - } - if (ch == ']') { - ipv6Host = false; - } - if (ch != '%' || ipv6Host) { - continue; - } - - if (count < 3) { - throw new FileSystemException("vfs.provider/invalid-escape-sequence.error", - buffer.substring(index, index + count)); - } - - // Decode - final int dig1 = Character.digit(buffer.charAt(index + 1), HEX_BASE); - final int dig2 = Character.digit(buffer.charAt(index + 2), HEX_BASE); - if (dig1 == -1 || dig2 == -1) { - throw new FileSystemException("vfs.provider/invalid-escape-sequence.error", - buffer.substring(index, index + 3)); - } - final char value = (char) (dig1 << BITS_IN_HALF_BYTE | dig2); - - // Replace - buffer.setCharAt(index, value); - buffer.delete(index + 1, index + 3); - count -= 2; - } - } - - /** - * Converts "special" characters to their %nn value. - * - * @param decodedStr The decoded String. - * @return The encoded String. - */ - public static String encode(final String decodedStr) { - return encode(decodedStr, null); - } - - /** - * Converts "special" characters to their %nn value. - * - * @param decodedStr The decoded String. - * @param reserved Characters to encode. - * @return The encoded String - */ - public static String encode(final String decodedStr, final char[] reserved) { - if (decodedStr == null) { - return null; - } - final StringBuilder buffer = new StringBuilder(decodedStr); - encode(buffer, 0, buffer.length(), reserved); - return buffer.toString(); - } - - /** - * Encode an array of Strings. - * - * @param strings The array of Strings to encode. - * @return An array of encoded Strings. - */ - public static String[] encode(final String[] strings) { - if (strings == null) { - return null; - } - Arrays.setAll(strings, i -> encode(strings[i])); - return strings; - } - - /** - * Encodes a set of reserved characters in a StringBuilder, using the URI %nn encoding. Always encodes % characters. - * - * @param buffer The StringBuilder to append to. - * @param offset The position in the buffer to start encoding at. - * @param length The number of characters to encode. - * @param reserved characters to encode. - */ - public static void encode(final StringBuilder buffer, final int offset, final int length, final char[] reserved) { - int index = offset; - int count = length; - for (; count > 0; index++, count--) { - final char ch = buffer.charAt(index); - boolean match = ch == '%'; - if (reserved != null) { - for (int i = 0; !match && i < reserved.length; i++) { - if (ch == reserved[i]) { - match = true; - break; - } - } - } - if (match) { - // Encode - final char[] digits = {Character.forDigit(ch >> BITS_IN_HALF_BYTE & LOW_MASK, HEX_BASE), Character.forDigit(ch & LOW_MASK, HEX_BASE)}; - buffer.setCharAt(index, '%'); - buffer.insert(index + 1, digits); - index += 2; - } - } - } - - static void encodeRfc2396(final StringBuilder buffer, final int offset, final int length, final char[] allowed) { - int index = offset; - int count = length; - for (; count > 0; index++, count--) { - final char ch = buffer.charAt(index); - if (Arrays.binarySearch(allowed, ch) < 0) { - // Encode - final char[] digits = {Character.forDigit(ch >> BITS_IN_HALF_BYTE & LOW_MASK, HEX_BASE), Character.forDigit(ch & LOW_MASK, HEX_BASE)}; - buffer.setCharAt(index, '%'); - buffer.insert(index + 1, digits); - index += 2; - } - } - } - - /** - * Extracts the first element of a path. - * - * @param name StringBuilder containing the path. - * @return The first element of the path. - */ - public static String extractFirstElement(final StringBuilder name) { - final int len = name.length(); - if (len < 1) { - return null; - } - int startPos = 0; - if (name.charAt(0) == SEPARATOR_CHAR) { - startPos = 1; - } - for (int pos = startPos; pos < len; pos++) { - if (name.charAt(pos) == SEPARATOR_CHAR) { - // Found a separator - final String elem = name.substring(startPos, pos); - name.delete(startPos, pos + 1); - return elem; - } - } - - // No separator - final String elem = name.substring(startPos); - name.setLength(0); - return elem; - } - - /** - * Extract the query String from the URI. - * - * @param name StringBuilder containing the URI. - * @return The query string, if any. null otherwise. - */ - public static String extractQueryString(final StringBuilder name) { - for (int pos = 0; pos < name.length(); pos++) { - if (name.charAt(pos) == '?') { - final String queryString = name.substring(pos + 1); - name.delete(pos, name.length()); - return queryString; - } - } - - return null; - } - - /** - * Extracts the scheme from a URI. - * - * @param uri The URI. - * @return The scheme name. Returns null if there is no scheme. - * @deprecated Use instead {@link #extractScheme}. Will be removed in 3.0. - */ - @Deprecated - public static String extractScheme(final String uri) { - return extractScheme(uri, null); - } - - /** - * Extracts the scheme from a URI. Removes the scheme and ':' delimiter from the front of the URI. - * - * @param uri The URI. - * @param buffer Returns the remainder of the URI. - * @return The scheme name. Returns null if there is no scheme. - * @deprecated Use instead {@link #extractScheme}. Will be removed in 3.0. - */ - @Deprecated - public static String extractScheme(final String uri, final StringBuilder buffer) { - if (buffer != null) { - buffer.setLength(0); - buffer.append(uri); - } - - final int maxPos = uri.length(); - for (int pos = 0; pos < maxPos; pos++) { - final char ch = uri.charAt(pos); - - if (ch == ':') { - // Found the end of the scheme - final String scheme = uri.substring(0, pos); - if (scheme.length() <= 1 && SystemUtils.IS_OS_WINDOWS) { - // This is not a scheme, but a Windows drive letter - return null; - } - if (buffer != null) { - buffer.delete(0, pos + 1); - } - return scheme.intern(); - } - - if (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z') { - // A scheme character - continue; - } - if (!(pos > 0 && (ch >= '0' && ch <= '9' || ch == '+' || ch == '-' || ch == '.'))) { - // Not a scheme character - break; - } - // A scheme character (these are not allowed as the first - // character of the scheme), but can be used as subsequent - // characters. - } - - // No scheme in URI - return null; - } - - /** - * Extracts the scheme from a URI. Removes the scheme and ':' delimiter from the front of the URI. - *

- * The scheme is extracted based on the currently supported schemes in the system. That is to say the schemes - * supported by the registered providers. - *

- *

- * This allows us to handle varying scheme's without making assumptions based on the ':' character. Specifically - * handle scheme extraction calls for URI parameters that are not actually uri's, but may be names with ':' in them. - *

- * @param schemes The schemes to check. - * @param uri The potential URI. May also be a name. - * @return The scheme name. Returns null if there is no scheme. - * @since 2.3 - */ - public static String extractScheme(final String[] schemes, final String uri) { - return extractScheme(schemes, uri, null); - } - - /** - * Extracts the scheme from a URI. Removes the scheme and ':' delimiter from the front of the URI. - *

- * The scheme is extracted based on the given set of schemes. Normally, that is to say the schemes - * supported by the registered providers. - *

- *

- * This allows us to handle varying scheme's without making assumptions based on the ':' character. Specifically - * handle scheme extraction calls for URI parameters that are not actually URI's, but may be names with ':' in them. - *

- * @param schemes The schemes to check. - * @param uri The potential URI. May also just be a name. - * @param buffer Returns the remainder of the URI. - * @return The scheme name. Returns null if there is no scheme. - * @since 2.3 - */ - public static String extractScheme(final String[] schemes, final String uri, final StringBuilder buffer) { - if (buffer != null) { - buffer.setLength(0); - buffer.append(uri); - } - for (final String scheme : schemes) { - if (uri.startsWith(scheme + ":")) { - if (buffer != null) { - buffer.delete(0, uri.indexOf(':') + 1); - } - return scheme; - } - } - return null; - } - - /** - * Normalises the separators in a name. - * - * @param name The StringBuilder containing the name - * @return true if the StringBuilder was modified. - */ - public static boolean fixSeparators(final StringBuilder name) { - boolean changed = false; - int maxlen = name.length(); - for (int i = 0; i < maxlen; i++) { - final char ch = name.charAt(i); - if (ch == TRANS_SEPARATOR) { - name.setCharAt(i, SEPARATOR_CHAR); - changed = true; - } - if (i < maxlen - 2 && name.charAt(i) == '%' && name.charAt(i + 1) == '2') { - if (name.charAt(i + 2) == 'f' || name.charAt(i + 2) == 'F') { - name.setCharAt(i, SEPARATOR_CHAR); - name.delete(i + 1, i + 3); - maxlen -= 2; - changed = true; - } else if (name.charAt(i + 2) == 'e' || name.charAt(i + 2) == 'E') { - name.setCharAt(i, '.'); - name.delete(i + 1, i + 3); - maxlen -= 2; - changed = true; - } - } - } - return changed; - } - - /** - * Normalises a path. Does the following: - *
    - *
  • Removes empty path elements. - *
  • Handles '.' and '..' elements. - *
  • Removes trailing separator. - *
- * - * Its assumed that the separators are already fixed. - * - * @param path The path to normalize. - * @return The FileType. - * @throws FileSystemException if an error occurs. - * @see #fixSeparators - */ - public static FileType normalisePath(final StringBuilder path) throws FileSystemException { - FileType fileType = FileType.FOLDER; - if (path.length() == 0) { - return fileType; - } - - // '/' or '.' or '..' or anyPath/..' or 'anyPath/.' should always be a path - if (path.charAt(path.length() - 1) != '/' - && path.lastIndexOf("/..") != path.length() - 3 - && path.lastIndexOf("/.") != path.length() - 2 - && path.lastIndexOf("..") != 0 - && path.lastIndexOf(".") != 0 - ) { - fileType = FileType.FILE; - } - - // Adjust separators - // fixSeparators(path); - - // Determine the start of the first element - int startFirstElem = 0; - if (path.charAt(0) == SEPARATOR_CHAR) { - if (path.length() == 1) { - return fileType; - } - startFirstElem = 1; - } - - // Iterate over each element - int startElem = startFirstElem; - int maxlen = path.length(); - while (startElem < maxlen) { - // Find the end of the element - int endElem = startElem; - while (endElem < maxlen && path.charAt(endElem) != SEPARATOR_CHAR) { - endElem++; - } - - final int elemLen = endElem - startElem; - if (elemLen == 0) { - // An empty element - axe it - path.deleteCharAt(endElem); - maxlen = path.length(); - continue; - } - if (elemLen == 1 && path.charAt(startElem) == '.') { - // A '.' element - axe it - path.deleteCharAt(startElem); - maxlen = path.length(); - continue; - } - if (elemLen == 2 && path.charAt(startElem) == '.' && path.charAt(startElem + 1) == '.') { - // A '..' element - remove the previous element - if (startElem == startFirstElem) { - // Previous element is missing - throw new FileSystemException("vfs.provider/invalid-relative-path.error"); - } - - // Find start of previous element - int pos = startElem - 2; - while (pos >= 0 && path.charAt(pos) != SEPARATOR_CHAR) { - pos--; - } - startElem = pos + 1; - - path.delete(startElem, endElem + 1); - maxlen = path.length(); - continue; - } - - // A regular element - startElem = endElem + 1; - } - - // Remove trailing separator - if (!VFS.isUriStyle() && maxlen > 1 && path.charAt(maxlen - 1) == SEPARATOR_CHAR) { - path.deleteCharAt(maxlen - 1); - } - - return fileType; - } - - private UriParser() { - } -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.vfs2.provider; + +import java.util.Arrays; + +import org.apache.commons.lang3.SystemUtils; +import org.apache.commons.vfs2.FileName; +import org.apache.commons.vfs2.FileSystemException; +import org.apache.commons.vfs2.FileType; +import org.apache.commons.vfs2.VFS; + +/** + * Utilities for dealing with URIs. See RFC 2396 for details. + */ +public final class UriParser { + + /** + * The set of valid separators. These are all converted to the normalized one. Does not contain the + * normalized separator + */ + // public static final char[] separators = {'\\'}; + public static final char TRANS_SEPARATOR = '\\'; + + /** + * The normalised separator to use. + */ + private static final char SEPARATOR_CHAR = FileName.SEPARATOR_CHAR; + + private static final int HEX_BASE = 16; + + private static final int BITS_IN_HALF_BYTE = 4; + + private static final char LOW_MASK = 0x0F; + + /** + * Encodes and appends a string to a StringBuilder. + * + * @param buffer The StringBuilder to append to. + * @param unencodedValue The String to encode and append. + * @param reserved characters to encode. + */ + public static void appendEncoded(final StringBuilder buffer, final String unencodedValue, final char[] reserved) { + final int offset = buffer.length(); + buffer.append(unencodedValue); + encode(buffer, offset, unencodedValue.length(), reserved); + } + + static void appendEncodedRfc2396(final StringBuilder buffer, final String unencodedValue, final char[] allowed) { + final int offset = buffer.length(); + buffer.append(unencodedValue); + encodeRfc2396(buffer, offset, unencodedValue.length(), allowed); + } + + /** + * Canonicalizes a path. + * + * @param buffer Source data. + * @param offset Where to start reading. + * @param length How much to read. + * @param fileNameParser Now to encode and decode. + * @throws FileSystemException If an I/O error occurs. + */ + public static void canonicalizePath(final StringBuilder buffer, final int offset, final int length, + final FileNameParser fileNameParser) throws FileSystemException { + int index = offset; + int count = length; + for (; count > 0; count--, index++) { + final char ch = buffer.charAt(index); + if (ch == '%') { + if (count < 3) { + throw new FileSystemException("vfs.provider/invalid-escape-sequence.error", + buffer.substring(index, index + count)); + } + + // Decode + final int dig1 = Character.digit(buffer.charAt(index + 1), HEX_BASE); + final int dig2 = Character.digit(buffer.charAt(index + 2), HEX_BASE); + if (dig1 == -1 || dig2 == -1) { + throw new FileSystemException("vfs.provider/invalid-escape-sequence.error", + buffer.substring(index, index + 3)); + } + final char value = (char) (dig1 << BITS_IN_HALF_BYTE | dig2); + + final boolean match = value == '%' || fileNameParser.encodeCharacter(value); + + if (match) { + // this is a reserved character, not allowed to decode + index += 2; + count -= 2; + continue; + } + + // Replace + buffer.setCharAt(index, value); + buffer.delete(index + 1, index + 3); + count -= 2; + } else if (fileNameParser.encodeCharacter(ch)) { + // Encode + final char[] digits = {Character.forDigit(ch >> BITS_IN_HALF_BYTE & LOW_MASK, HEX_BASE), Character.forDigit(ch & LOW_MASK, HEX_BASE)}; + buffer.setCharAt(index, '%'); + buffer.insert(index + 1, digits); + index += 2; + } + } + } + + /** + * Decodes the String. + * + * @param uri The String to decode. + * @throws FileSystemException if an error occurs. + */ + public static void checkUriEncoding(final String uri) throws FileSystemException { + decode(uri); + } + + /** + * Removes %nn encodings from a string. + * + * @param encodedStr The encoded String. + * @return The decoded String. + * @throws FileSystemException if an error occurs. + */ + public static String decode(final String encodedStr) throws FileSystemException { + if (encodedStr == null) { + return null; + } + if (encodedStr.indexOf('%') < 0) { + return encodedStr; + } + final StringBuilder buffer = new StringBuilder(encodedStr); + decode(buffer, 0, buffer.length()); + return buffer.toString(); + } + + /** + * Removes %nn encodings from a string. + * + * @param buffer StringBuilder containing the string to decode. + * @param offset The position in the string to start decoding. + * @param length The number of characters to decode. + * @throws FileSystemException if an error occurs. + */ + public static void decode(final StringBuilder buffer, final int offset, final int length) + throws FileSystemException { + int index = offset; + int count = length; + boolean ipv6Host = false; + for (; count > 0; count--, index++) { + final char ch = buffer.charAt(index); + if (ch == '[') { + ipv6Host = true; + } + if (ch == ']') { + ipv6Host = false; + } + if (ch != '%' || ipv6Host) { + continue; + } + + if (count < 3) { + throw new FileSystemException("vfs.provider/invalid-escape-sequence.error", + buffer.substring(index, index + count)); + } + + // Decode + final int dig1 = Character.digit(buffer.charAt(index + 1), HEX_BASE); + final int dig2 = Character.digit(buffer.charAt(index + 2), HEX_BASE); + if (dig1 == -1 || dig2 == -1) { + throw new FileSystemException("vfs.provider/invalid-escape-sequence.error", + buffer.substring(index, index + 3)); + } + final char value = (char) (dig1 << BITS_IN_HALF_BYTE | dig2); + + // Replace + buffer.setCharAt(index, value); + buffer.delete(index + 1, index + 3); + count -= 2; + } + } + + /** + * Converts "special" characters to their %nn value. + * + * @param decodedStr The decoded String. + * @return The encoded String. + */ + public static String encode(final String decodedStr) { + return encode(decodedStr, null); + } + + /** + * Converts "special" characters to their %nn value. + * + * @param decodedStr The decoded String. + * @param reserved Characters to encode. + * @return The encoded String + */ + public static String encode(final String decodedStr, final char[] reserved) { + if (decodedStr == null) { + return null; + } + final StringBuilder buffer = new StringBuilder(decodedStr); + encode(buffer, 0, buffer.length(), reserved); + return buffer.toString(); + } + + /** + * Encode an array of Strings. + * + * @param strings The array of Strings to encode. + * @return An array of encoded Strings. + */ + public static String[] encode(final String[] strings) { + if (strings == null) { + return null; + } + Arrays.setAll(strings, i -> encode(strings[i])); + return strings; + } + + /** + * Encodes a set of reserved characters in a StringBuilder, using the URI %nn encoding. Always encodes % characters. + * + * @param buffer The StringBuilder to append to. + * @param offset The position in the buffer to start encoding at. + * @param length The number of characters to encode. + * @param reserved characters to encode. + */ + public static void encode(final StringBuilder buffer, final int offset, final int length, final char[] reserved) { + int index = offset; + int count = length; + for (; count > 0; index++, count--) { + final char ch = buffer.charAt(index); + boolean match = ch == '%'; + if (reserved != null) { + for (int i = 0; !match && i < reserved.length; i++) { + if (ch == reserved[i]) { + match = true; + break; + } + } + } + if (match) { + // Encode + final char[] digits = {Character.forDigit(ch >> BITS_IN_HALF_BYTE & LOW_MASK, HEX_BASE), Character.forDigit(ch & LOW_MASK, HEX_BASE)}; + buffer.setCharAt(index, '%'); + buffer.insert(index + 1, digits); + index += 2; + } + } + } + + static void encodeRfc2396(final StringBuilder buffer, final int offset, final int length, final char[] allowed) { + int index = offset; + int count = length; + for (; count > 0; index++, count--) { + final char ch = buffer.charAt(index); + if (Arrays.binarySearch(allowed, ch) < 0) { + // Encode + final char[] digits = {Character.forDigit(ch >> BITS_IN_HALF_BYTE & LOW_MASK, HEX_BASE), Character.forDigit(ch & LOW_MASK, HEX_BASE)}; + buffer.setCharAt(index, '%'); + buffer.insert(index + 1, digits); + index += 2; + } + } + } + + /** + * Extracts the first element of a path. + * + * @param name StringBuilder containing the path. + * @return The first element of the path. + */ + public static String extractFirstElement(final StringBuilder name) { + final int len = name.length(); + if (len < 1) { + return null; + } + int startPos = 0; + if (name.charAt(0) == SEPARATOR_CHAR) { + startPos = 1; + } + for (int pos = startPos; pos < len; pos++) { + if (name.charAt(pos) == SEPARATOR_CHAR) { + // Found a separator + final String elem = name.substring(startPos, pos); + name.delete(startPos, pos + 1); + return elem; + } + } + + // No separator + final String elem = name.substring(startPos); + name.setLength(0); + return elem; + } + + /** + * Extract the query String from the URI. + * + * @param name StringBuilder containing the URI. + * @return The query string, if any. null otherwise. + */ + public static String extractQueryString(final StringBuilder name) { + for (int pos = 0; pos < name.length(); pos++) { + if (name.charAt(pos) == '?') { + final String queryString = name.substring(pos + 1); + name.delete(pos, name.length()); + return queryString; + } + } + + return null; + } + + /** + * Extracts the scheme from a URI. + * + * @param uri The URI. + * @return The scheme name. Returns null if there is no scheme. + * @deprecated Use instead {@link #extractScheme}. Will be removed in 3.0. + */ + @Deprecated + public static String extractScheme(final String uri) { + return extractScheme(uri, null); + } + + /** + * Extracts the scheme from a URI. Removes the scheme and ':' delimiter from the front of the URI. + * + * @param uri The URI. + * @param buffer Returns the remainder of the URI. + * @return The scheme name. Returns null if there is no scheme. + * @deprecated Use instead {@link #extractScheme}. Will be removed in 3.0. + */ + @Deprecated + public static String extractScheme(final String uri, final StringBuilder buffer) { + if (buffer != null) { + buffer.setLength(0); + buffer.append(uri); + } + + final int maxPos = uri.length(); + for (int pos = 0; pos < maxPos; pos++) { + final char ch = uri.charAt(pos); + + if (ch == ':') { + // Found the end of the scheme + final String scheme = uri.substring(0, pos); + if (scheme.length() <= 1 && SystemUtils.IS_OS_WINDOWS) { + // This is not a scheme, but a Windows drive letter + return null; + } + if (buffer != null) { + buffer.delete(0, pos + 1); + } + return scheme.intern(); + } + + if (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z') { + // A scheme character + continue; + } + if (!(pos > 0 && (ch >= '0' && ch <= '9' || ch == '+' || ch == '-' || ch == '.'))) { + // Not a scheme character + break; + } + // A scheme character (these are not allowed as the first + // character of the scheme), but can be used as subsequent + // characters. + } + + // No scheme in URI + return null; + } + + /** + * Extracts the scheme from a URI. Removes the scheme and ':' delimiter from the front of the URI. + *

+ * The scheme is extracted based on the currently supported schemes in the system. That is to say the schemes + * supported by the registered providers. + *

+ *

+ * This allows us to handle varying scheme's without making assumptions based on the ':' character. Specifically + * handle scheme extraction calls for URI parameters that are not actually uri's, but may be names with ':' in them. + *

+ * @param schemes The schemes to check. + * @param uri The potential URI. May also be a name. + * @return The scheme name. Returns null if there is no scheme. + * @since 2.3 + */ + public static String extractScheme(final String[] schemes, final String uri) { + return extractScheme(schemes, uri, null); + } + + /** + * Extracts the scheme from a URI. Removes the scheme and ':' delimiter from the front of the URI. + *

+ * The scheme is extracted based on the given set of schemes. Normally, that is to say the schemes + * supported by the registered providers. + *

+ *

+ * This allows us to handle varying scheme's without making assumptions based on the ':' character. Specifically + * handle scheme extraction calls for URI parameters that are not actually URI's, but may be names with ':' in them. + *

+ * @param schemes The schemes to check. + * @param uri The potential URI. May also just be a name. + * @param buffer Returns the remainder of the URI. + * @return The scheme name. Returns null if there is no scheme. + * @since 2.3 + */ + public static String extractScheme(final String[] schemes, final String uri, final StringBuilder buffer) { + if (buffer != null) { + buffer.setLength(0); + buffer.append(uri); + } + for (final String scheme : schemes) { + if (uri.startsWith(scheme + ":")) { + if (buffer != null) { + buffer.delete(0, uri.indexOf(':') + 1); + } + return scheme; + } + } + return null; + } + + /** + * Normalises the separators in a name. + * + * @param name The StringBuilder containing the name + * @return true if the StringBuilder was modified. + */ + public static boolean fixSeparators(final StringBuilder name) { + boolean changed = false; + int maxlen = name.length(); + for (int i = 0; i < maxlen; i++) { + final char ch = name.charAt(i); + if (ch == TRANS_SEPARATOR) { + name.setCharAt(i, SEPARATOR_CHAR); + changed = true; + } + if (i < maxlen - 2 && name.charAt(i) == '%' && name.charAt(i + 1) == '2') { + if (name.charAt(i + 2) == 'f' || name.charAt(i + 2) == 'F') { + name.setCharAt(i, SEPARATOR_CHAR); + name.delete(i + 1, i + 3); + maxlen -= 2; + changed = true; + } else if (name.charAt(i + 2) == 'e' || name.charAt(i + 2) == 'E') { + name.setCharAt(i, '.'); + name.delete(i + 1, i + 3); + maxlen -= 2; + changed = true; + } + } + } + return changed; + } + + /** + * Normalises a path. Does the following: + *
    + *
  • Removes empty path elements. + *
  • Handles '.' and '..' elements. + *
  • Removes trailing separator. + *
+ * + * Its assumed that the separators are already fixed. + * + * @param path The path to normalize. + * @return The FileType. + * @throws FileSystemException if an error occurs. + * @see #fixSeparators + */ + public static FileType normalisePath(final StringBuilder path) throws FileSystemException { + FileType fileType = FileType.FOLDER; + if (path.length() == 0) { + return fileType; + } + + // '/' or '.' or '..' or anyPath/..' or 'anyPath/.' should always be a path + if (path.charAt(path.length() - 1) != '/' + && path.lastIndexOf("/..") != path.length() - 3 + && path.lastIndexOf("/.") != path.length() - 2 + && path.lastIndexOf("..") != 0 + && path.lastIndexOf(".") != 0 + ) { + fileType = FileType.FILE; + } + + // Adjust separators + // fixSeparators(path); + + // Determine the start of the first element + int startFirstElem = 0; + if (path.charAt(0) == SEPARATOR_CHAR) { + if (path.length() == 1) { + return fileType; + } + startFirstElem = 1; + } + + // Iterate over each element + int startElem = startFirstElem; + int maxlen = path.length(); + while (startElem < maxlen) { + // Find the end of the element + int endElem = startElem; + while (endElem < maxlen && path.charAt(endElem) != SEPARATOR_CHAR) { + endElem++; + } + + final int elemLen = endElem - startElem; + if (elemLen == 0) { + // An empty element - axe it + path.deleteCharAt(endElem); + maxlen = path.length(); + continue; + } + if (elemLen == 1 && path.charAt(startElem) == '.') { + // A '.' element - axe it + path.deleteCharAt(startElem); + maxlen = path.length(); + continue; + } + if (elemLen == 2 && path.charAt(startElem) == '.' && path.charAt(startElem + 1) == '.') { + // A '..' element - remove the previous element + if (startElem == startFirstElem) { + // Previous element is missing + throw new FileSystemException("vfs.provider/invalid-relative-path.error"); + } + + // Find start of previous element + int pos = startElem - 2; + while (pos >= 0 && path.charAt(pos) != SEPARATOR_CHAR) { + pos--; + } + startElem = pos + 1; + + path.delete(startElem, endElem + 1); + maxlen = path.length(); + continue; + } + + // A regular element + startElem = endElem + 1; + } + + // Remove trailing separator + if (!VFS.isUriStyle() && maxlen > 1 && path.charAt(maxlen - 1) == SEPARATOR_CHAR) { + path.deleteCharAt(maxlen - 1); + } + + return fileType; + } + + private UriParser() { + } +} diff --git a/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/ftp/FtpFileObject.java b/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/ftp/FtpFileObject.java index dafc4f00ef..09c03aaad6 100644 --- a/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/ftp/FtpFileObject.java +++ b/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/ftp/FtpFileObject.java @@ -1,651 +1,651 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.vfs2.provider.ftp; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.time.Instant; -import java.util.Calendar; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.TimeZone; -import java.util.TreeMap; -import java.util.concurrent.atomic.AtomicBoolean; - -import org.apache.commons.io.function.Uncheck; -import org.apache.commons.lang3.ArrayUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.commons.net.ftp.FTPFile; -import org.apache.commons.vfs2.FileName; -import org.apache.commons.vfs2.FileNotFolderException; -import org.apache.commons.vfs2.FileNotFoundException; -import org.apache.commons.vfs2.FileObject; -import org.apache.commons.vfs2.FileSystemException; -import org.apache.commons.vfs2.FileType; -import org.apache.commons.vfs2.RandomAccessContent; -import org.apache.commons.vfs2.provider.AbstractFileName; -import org.apache.commons.vfs2.provider.AbstractFileObject; -import org.apache.commons.vfs2.provider.UriParser; -import org.apache.commons.vfs2.util.FileObjectUtils; -import org.apache.commons.vfs2.util.Messages; -import org.apache.commons.vfs2.util.MonitorInputStream; -import org.apache.commons.vfs2.util.MonitorOutputStream; -import org.apache.commons.vfs2.util.RandomAccessMode; - -/** - * An FTP file. - */ -public class FtpFileObject extends AbstractFileObject { - - /** - * An InputStream that monitors for end-of-file. - */ - final class FtpInputStream extends MonitorInputStream { - private final FtpClient client; - - FtpInputStream(final FtpClient client, final InputStream in) { - super(in); - this.client = client; - } - - FtpInputStream(final FtpClient client, final InputStream in, final int bufferSize) { - super(in, bufferSize); - this.client = client; - } - - void abort() throws IOException { - client.abort(); - close(); - } - - private boolean isTransferAbortedOkReplyCode() throws IOException { - final List transferAbortedOkReplyCodes = FtpFileSystemConfigBuilder - .getInstance() - .getTransferAbortedOkReplyCodes(getAbstractFileSystem().getFileSystemOptions()); - return transferAbortedOkReplyCodes != null && transferAbortedOkReplyCodes.contains(client.getReplyCode()); - } - - /** - * Called after the stream has been closed. - */ - @Override - protected void onClose() throws IOException { - final boolean ok; - try { - ok = client.completePendingCommand() || isTransferAbortedOkReplyCode(); - } finally { - getAbstractFileSystem().putClient(client); - } - - if (!ok) { - throw new FileSystemException("vfs.provider.ftp/finish-get.error", getName()); - } - } - } - /** - * An OutputStream that monitors for end-of-file. - */ - private final class FtpOutputStream extends MonitorOutputStream { - private final FtpClient client; - - FtpOutputStream(final FtpClient client, final OutputStream outstr) { - super(outstr); - this.client = client; - } - - /** - * Called after this stream is closed. - */ - @Override - protected void onClose() throws IOException { - final boolean ok; - try { - ok = client.completePendingCommand(); - } finally { - getAbstractFileSystem().putClient(client); - } - - if (!ok) { - throw new FileSystemException("vfs.provider.ftp/finish-put.error", getName()); - } - } - } - - private static final long DEFAULT_TIMESTAMP = 0L; - private static final Map EMPTY_FTP_FILE_MAP = Collections - .unmodifiableMap(new TreeMap<>()); - - private static final FTPFile UNKNOWN = new FTPFile(); - - private static final Log log = LogFactory.getLog(FtpFileObject.class); - private volatile boolean mdtmSet; - private final String relPath; - // Cached info - private volatile FTPFile ftpFile; - private volatile Map childMap; - - private volatile FileObject linkDestination; - - private final AtomicBoolean inRefresh = new AtomicBoolean(); - - /** - * Constructs a new instance. - * - * @param fileName the file name. - * @param fileSystem the file system. - * @param rootName the root name. - * @throws FileSystemException if an file system error occurs. - */ - protected FtpFileObject(final AbstractFileName fileName, final FtpFileSystem fileSystem, final FileName rootName) - throws FileSystemException { - super(fileName, fileSystem); - final String relPath = UriParser.decode(rootName.getRelativeName(fileName)); - if (".".equals(relPath)) { - // do not use the "." as path against the ftp-server - // e.g. the uu.net ftp-server do a recursive listing then - // this.relPath = UriParser.decode(rootName.getPath()); - // this.relPath = "."; - this.relPath = null; - } else { - this.relPath = relPath; - } - } - - /** - * Attaches this file object to its file resource. - */ - @Override - protected void doAttach() throws IOException { - // Get the parent folder to find the info for this file - // VFS-210 getInfo(false); - } - - /** - * Creates this file as a folder. - */ - @Override - protected void doCreateFolder() throws Exception { - final boolean ok; - final FtpClient client = getAbstractFileSystem().getClient(); - try { - ok = client.makeDirectory(relPath); - } finally { - getAbstractFileSystem().putClient(client); - } - - if (!ok) { - throw new FileSystemException("vfs.provider.ftp/create-folder.error", getName()); - } - } - - /** - * Deletes the file. - */ - @Override - protected void doDelete() throws Exception { - synchronized (getFileSystem()) { - if (ftpFile != null) { - final boolean ok; - final FtpClient ftpClient = getAbstractFileSystem().getClient(); - try { - if (ftpFile.isDirectory()) { - ok = ftpClient.removeDirectory(relPath); - } else { - ok = ftpClient.deleteFile(relPath); - } - } finally { - getAbstractFileSystem().putClient(ftpClient); - } - - if (!ok) { - throw new FileSystemException("vfs.provider.ftp/delete-file.error", getName()); - } - ftpFile = null; - } - childMap = EMPTY_FTP_FILE_MAP; - } - } - - /** - * Detaches this file object from its file resource. - */ - @Override - protected void doDetach() { - synchronized (getFileSystem()) { - ftpFile = null; - childMap = null; - mdtmSet = false; - } - } - - /** - * Fetches the children of this file, if not already cached. - */ - private void doGetChildren() throws IOException { - if (childMap != null) { - return; - } - - final FtpClient client = getAbstractFileSystem().getClient(); - try { - final String path = ftpFile != null && ftpFile.isSymbolicLink() - ? getFileSystem().getFileSystemManager().resolveName(getParent().getName(), ftpFile.getLink()) - .getPath() - : relPath; - final FTPFile[] tmpChildren = client.listFiles(path); - if (ArrayUtils.isEmpty(tmpChildren)) { - childMap = EMPTY_FTP_FILE_MAP; - } else { - childMap = new TreeMap<>(); - - // Remove '.' and '..' elements - for (int i = 0; i < tmpChildren.length; i++) { - final FTPFile child = tmpChildren[i]; - if (child == null) { - if (log.isDebugEnabled()) { - log.debug(Messages.getString("vfs.provider.ftp/invalid-directory-entry.debug", - Integer.valueOf(i), relPath)); - } - continue; - } - if (!".".equals(child.getName()) && !"..".equals(child.getName())) { - childMap.put(child.getName(), child); - } - } - } - } finally { - getAbstractFileSystem().putClient(client); - } - } - - /** - * Returns the size of the file content (in bytes). - */ - @Override - protected long doGetContentSize() throws Exception { - synchronized (getFileSystem()) { - if (ftpFile == null) { - return 0; - } - if (ftpFile.isSymbolicLink()) { - final FileObject linkDest = getLinkDestination(); - // VFS-437: Try to avoid a recursion loop. - if (isCircular(linkDest)) { - return ftpFile.getSize(); - } - return linkDest.getContent().getSize(); - } - return ftpFile.getSize(); - } - } - - /** - * Creates an input stream to read the file content from. - */ - @Override - protected InputStream doGetInputStream(final int bufferSize) throws Exception { - final FtpClient client = getAbstractFileSystem().getClient(); - try { - final InputStream inputStream = client.retrieveFileStream(relPath, 0); - // VFS-210 - if (inputStream == null) { - throw new FileNotFoundException(getName().toString()); - } - return new FtpInputStream(client, inputStream, bufferSize); - } catch (final Exception e) { - getAbstractFileSystem().putClient(client); - throw e; - } - } - - /** - * Gets the last modified time on an FTP file - * - * @see org.apache.commons.vfs2.provider.AbstractFileObject#doGetLastModifiedTime() - */ - @Override - protected long doGetLastModifiedTime() throws Exception { - synchronized (getFileSystem()) { - if (ftpFile == null) { - return DEFAULT_TIMESTAMP; - } - if (ftpFile.isSymbolicLink()) { - final FileObject linkDest = getLinkDestination(); - // VFS-437: Try to avoid a recursion loop. - if (isCircular(linkDest)) { - return getTimestampMillis(); - } - return linkDest.getContent().getLastModifiedTime(); - } - return getTimestampMillis(); - } - } - - /** - * Creates an output stream to write the file content to. - */ - @Override - protected OutputStream doGetOutputStream(final boolean bAppend) throws Exception { - final FtpClient client = getAbstractFileSystem().getClient(); - try { - final OutputStream out; - if (bAppend) { - out = client.appendFileStream(relPath); - } else { - out = client.storeFileStream(relPath); - } - - FileSystemException.requireNonNull(out, "vfs.provider.ftp/output-error.debug", getName(), - client.getReplyString()); - - return new FtpOutputStream(client, out); - } catch (final Exception e) { - getAbstractFileSystem().putClient(client); - throw e; - } - } - - @Override - protected RandomAccessContent doGetRandomAccessContent(final RandomAccessMode mode) throws Exception { - return new FtpRandomAccessContent(this, mode); - } - - /** - * Determines the type of the file, returns null if the file does not exist. - */ - @Override - protected FileType doGetType() throws Exception { - // VFS-210 - synchronized (getFileSystem()) { - if (ftpFile == null) { - setFTPFile(false); - } - - if (ftpFile == UNKNOWN) { - return FileType.IMAGINARY; - } - if (ftpFile.isDirectory()) { - return FileType.FOLDER; - } - if (ftpFile.isFile()) { - return FileType.FILE; - } - if (ftpFile.isSymbolicLink()) { - final FileObject linkDest = getLinkDestination(); - // VFS-437: We need to check if the symbolic link links back to the symbolic link itself - if (isCircular(linkDest)) { - // If the symbolic link links back to itself, treat it as an imaginary file to prevent following - // this link. If the user tries to access the link as a file or directory, the user will end up with - // a FileSystemException warning that the file cannot be accessed. This is to prevent the infinite - // call back to doGetType() to prevent the StackOverFlow - return FileType.IMAGINARY; - } - return linkDest.getType(); - - } - } - throw new FileSystemException("vfs.provider.ftp/get-type.error", getName()); - } - - /** - * Lists the children of the file. - */ - @Override - protected String[] doListChildren() throws Exception { - // List the children of this file - doGetChildren(); - - // VFS-210 - if (childMap == null) { - return null; - } - - // TODO - get rid of this children stuff - final String[] childNames = childMap.values().stream().filter(Objects::nonNull).map(FTPFile::getName).toArray(String[]::new); - - return UriParser.encode(childNames); - } - - @Override - protected FileObject[] doListChildrenResolved() throws Exception { - synchronized (getFileSystem()) { - if (ftpFile != null && ftpFile.isSymbolicLink()) { - final FileObject linkDest = getLinkDestination(); - // VFS-437: Try to avoid a recursion loop. - if (isCircular(linkDest)) { - return null; - } - return linkDest.getChildren(); - } - } - return null; - } - - /** - * Renames the file - */ - @Override - protected void doRename(final FileObject newFile) throws Exception { - synchronized (getFileSystem()) { - final boolean ok; - final FtpClient ftpClient = getAbstractFileSystem().getClient(); - try { - final String newName = ((FtpFileObject) FileObjectUtils.getAbstractFileObject(newFile)).getRelPath(); - ok = ftpClient.rename(relPath, newName); - } finally { - getAbstractFileSystem().putClient(ftpClient); - } - - if (!ok) { - throw new FileSystemException("vfs.provider.ftp/rename-file.error", getName().toString(), newFile); - } - ftpFile = null; - childMap = EMPTY_FTP_FILE_MAP; - } - } - - /** - * Called by child file objects, to locate their FTP file info. - * - * @param name the file name in its native form i.e. without URI stuff (%nn) - * @param flush recreate children cache - */ - private FTPFile getChildFile(final String name, final boolean flush) throws IOException { - /* - * If we should flush cached children, clear our children map unless we're in the middle of a refresh in which - * case we've just recently refreshed our children. No need to do it again when our children are refresh()ed, - * calling getChildFile() for themselves from within getInfo(). See getChildren(). - */ - if (flush && !inRefresh.get()) { - childMap = null; - } - - // List the children of this file - doGetChildren(); - - // Look for the requested child - // VFS-210 adds the null check. - return childMap != null ? childMap.get(name) : null; - } - - /** - * Returns the file's list of children. - * - * @return The list of children - * @throws FileSystemException If there was a problem listing children - * @see AbstractFileObject#getChildren() - * @since 2.0 - */ - @Override - public FileObject[] getChildren() throws FileSystemException { - try { - if (doGetType() != FileType.FOLDER) { - throw new FileNotFolderException(getName()); - } - } catch (final Exception ex) { - throw new FileNotFolderException(getName(), ex); - } - - try { - /* - * Wrap our parent implementation, noting that we're refreshing so that we don't refresh() ourselves and - * each of our parents for each child. Note that refresh() will list children. Meaning, if this file - * has C children, P parents, there will be (C * P) listings made with (C * (P + 1)) refreshes, when there - * should really only be 1 listing and C refreshes. - */ - inRefresh.set(true); - return super.getChildren(); - } finally { - inRefresh.set(false); - } - } - - FtpInputStream getInputStream(final long filePointer) throws IOException { - final FtpClient client = getAbstractFileSystem().getClient(); - try { - final InputStream instr = client.retrieveFileStream(relPath, filePointer); - FileSystemException.requireNonNull(instr, "vfs.provider.ftp/input-error.debug", getName(), - client.getReplyString()); - return new FtpInputStream(client, instr); - } catch (final IOException e) { - getAbstractFileSystem().putClient(client); - throw e; - } - } - - private FileObject getLinkDestination() throws FileSystemException { - if (linkDestination == null) { - final String path; - synchronized (getFileSystem()) { - path = ftpFile == null ? null : ftpFile.getLink(); - } - final FileName parent = getName().getParent(); - final FileName relativeTo = parent == null ? getName() : parent; - final FileName linkDestinationName = getFileSystem().getFileSystemManager().resolveName(relativeTo, path); - linkDestination = getFileSystem().resolveFile(linkDestinationName); - } - return linkDestination; - } - - String getRelPath() { - return relPath; - } - - /** - * ftpFile is not null. - */ - @SuppressWarnings("resource") // abstractFileSystem is managed in the superclass. - private long getTimestampMillis() throws IOException { - final FtpFileSystem abstractFileSystem = getAbstractFileSystem(); - final Boolean mdtmLastModifiedTime = FtpFileSystemConfigBuilder.getInstance() - .getMdtmLastModifiedTime(abstractFileSystem.getFileSystemOptions()); - if (mdtmLastModifiedTime != null && mdtmLastModifiedTime.booleanValue()) { - final FtpClient client = abstractFileSystem.getClient(); - if (!mdtmSet && client.hasFeature("MDTM")) { - final Instant mdtmInstant = client.mdtmInstant(relPath); - final Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT")); - final long epochMilli = mdtmInstant.toEpochMilli(); - calendar.setTimeInMillis(epochMilli); - ftpFile.setTimestamp(calendar); - mdtmSet = true; - } - } - return ftpFile.getTimestamp().getTime().getTime(); - } - - /** - * This is an over simplistic implementation for VFS-437. - */ - private boolean isCircular(final FileObject linkDest) throws FileSystemException { - return linkDest.getName().getPathDecoded().equals(getName().getPathDecoded()); - } - - /** - * Called when the type or content of this file changes. - */ - @Override - protected void onChange() throws IOException { - childMap = null; - - if (getType().equals(FileType.IMAGINARY)) { - // file is deleted, avoid server lookup - synchronized (getFileSystem()) { - ftpFile = UNKNOWN; - } - return; - } - - setFTPFile(true); - } - - /** - * Called when the children of this file change. - */ - @Override - protected void onChildrenChanged(final FileName child, final FileType newType) { - if (childMap != null && newType.equals(FileType.IMAGINARY)) { - Uncheck.run(() -> childMap.remove(UriParser.decode(child.getBaseName()))); - } else { - // if child was added we have to rescan the children - // TODO - get rid of this - childMap = null; - } - } - - /** - * @throws FileSystemException if an error occurs. - */ - @Override - public void refresh() throws FileSystemException { - if (inRefresh.compareAndSet(false, true)) { - try { - super.refresh(); - synchronized (getFileSystem()) { - ftpFile = null; - } - /* - * VFS-210 try { // this will tell the parent to recreate its children collection getInfo(true); } catch - * (IOException e) { throw new FileSystemException(e); } - */ - } finally { - inRefresh.set(false); - } - } - } - - /** - * Sets the internal FTPFile for this instance. - */ - private void setFTPFile(final boolean flush) throws IOException { - synchronized (getFileSystem()) { - final FtpFileObject parent = (FtpFileObject) FileObjectUtils.getAbstractFileObject(getParent()); - final FTPFile newFileInfo; - if (parent != null) { - newFileInfo = parent.getChildFile(UriParser.decode(getName().getBaseName()), flush); - } else { - // Assume the root is a directory and exists - newFileInfo = new FTPFile(); - newFileInfo.setType(FTPFile.DIRECTORY_TYPE); - } - ftpFile = newFileInfo == null ? UNKNOWN : newFileInfo; - } - } -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.vfs2.provider.ftp; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.time.Instant; +import java.util.Calendar; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.TimeZone; +import java.util.TreeMap; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.apache.commons.io.function.Uncheck; +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.commons.net.ftp.FTPFile; +import org.apache.commons.vfs2.FileName; +import org.apache.commons.vfs2.FileNotFolderException; +import org.apache.commons.vfs2.FileNotFoundException; +import org.apache.commons.vfs2.FileObject; +import org.apache.commons.vfs2.FileSystemException; +import org.apache.commons.vfs2.FileType; +import org.apache.commons.vfs2.RandomAccessContent; +import org.apache.commons.vfs2.provider.AbstractFileName; +import org.apache.commons.vfs2.provider.AbstractFileObject; +import org.apache.commons.vfs2.provider.UriParser; +import org.apache.commons.vfs2.util.FileObjectUtils; +import org.apache.commons.vfs2.util.Messages; +import org.apache.commons.vfs2.util.MonitorInputStream; +import org.apache.commons.vfs2.util.MonitorOutputStream; +import org.apache.commons.vfs2.util.RandomAccessMode; + +/** + * An FTP file. + */ +public class FtpFileObject extends AbstractFileObject { + + /** + * An InputStream that monitors for end-of-file. + */ + final class FtpInputStream extends MonitorInputStream { + private final FtpClient client; + + FtpInputStream(final FtpClient client, final InputStream in) { + super(in); + this.client = client; + } + + FtpInputStream(final FtpClient client, final InputStream in, final int bufferSize) { + super(in, bufferSize); + this.client = client; + } + + void abort() throws IOException { + client.abort(); + close(); + } + + private boolean isTransferAbortedOkReplyCode() throws IOException { + final List transferAbortedOkReplyCodes = FtpFileSystemConfigBuilder + .getInstance() + .getTransferAbortedOkReplyCodes(getAbstractFileSystem().getFileSystemOptions()); + return transferAbortedOkReplyCodes != null && transferAbortedOkReplyCodes.contains(client.getReplyCode()); + } + + /** + * Called after the stream has been closed. + */ + @Override + protected void onClose() throws IOException { + final boolean ok; + try { + ok = client.completePendingCommand() || isTransferAbortedOkReplyCode(); + } finally { + getAbstractFileSystem().putClient(client); + } + + if (!ok) { + throw new FileSystemException("vfs.provider.ftp/finish-get.error", getName()); + } + } + } + /** + * An OutputStream that monitors for end-of-file. + */ + private final class FtpOutputStream extends MonitorOutputStream { + private final FtpClient client; + + FtpOutputStream(final FtpClient client, final OutputStream outstr) { + super(outstr); + this.client = client; + } + + /** + * Called after this stream is closed. + */ + @Override + protected void onClose() throws IOException { + final boolean ok; + try { + ok = client.completePendingCommand(); + } finally { + getAbstractFileSystem().putClient(client); + } + + if (!ok) { + throw new FileSystemException("vfs.provider.ftp/finish-put.error", getName()); + } + } + } + + private static final long DEFAULT_TIMESTAMP = 0L; + private static final Map EMPTY_FTP_FILE_MAP = Collections + .unmodifiableMap(new TreeMap<>()); + + private static final FTPFile UNKNOWN = new FTPFile(); + + private static final Log log = LogFactory.getLog(FtpFileObject.class); + private volatile boolean mdtmSet; + private final String relPath; + // Cached info + private volatile FTPFile ftpFile; + private volatile Map childMap; + + private volatile FileObject linkDestination; + + private final AtomicBoolean inRefresh = new AtomicBoolean(); + + /** + * Constructs a new instance. + * + * @param fileName the file name. + * @param fileSystem the file system. + * @param rootName the root name. + * @throws FileSystemException if an file system error occurs. + */ + protected FtpFileObject(final AbstractFileName fileName, final FtpFileSystem fileSystem, final FileName rootName) + throws FileSystemException { + super(fileName, fileSystem); + final String relPath = UriParser.decode(rootName.getRelativeName(fileName)); + if (".".equals(relPath)) { + // do not use the "." as path against the ftp-server + // e.g. the uu.net ftp-server do a recursive listing then + // this.relPath = UriParser.decode(rootName.getPath()); + // this.relPath = "."; + this.relPath = null; + } else { + this.relPath = relPath; + } + } + + /** + * Attaches this file object to its file resource. + */ + @Override + protected void doAttach() throws IOException { + // Get the parent folder to find the info for this file + // VFS-210 getInfo(false); + } + + /** + * Creates this file as a folder. + */ + @Override + protected void doCreateFolder() throws Exception { + final boolean ok; + final FtpClient client = getAbstractFileSystem().getClient(); + try { + ok = client.makeDirectory(relPath); + } finally { + getAbstractFileSystem().putClient(client); + } + + if (!ok) { + throw new FileSystemException("vfs.provider.ftp/create-folder.error", getName()); + } + } + + /** + * Deletes the file. + */ + @Override + protected void doDelete() throws Exception { + synchronized (getFileSystem()) { + if (ftpFile != null) { + final boolean ok; + final FtpClient ftpClient = getAbstractFileSystem().getClient(); + try { + if (ftpFile.isDirectory()) { + ok = ftpClient.removeDirectory(relPath); + } else { + ok = ftpClient.deleteFile(relPath); + } + } finally { + getAbstractFileSystem().putClient(ftpClient); + } + + if (!ok) { + throw new FileSystemException("vfs.provider.ftp/delete-file.error", getName()); + } + ftpFile = null; + } + childMap = EMPTY_FTP_FILE_MAP; + } + } + + /** + * Detaches this file object from its file resource. + */ + @Override + protected void doDetach() { + synchronized (getFileSystem()) { + ftpFile = null; + childMap = null; + mdtmSet = false; + } + } + + /** + * Fetches the children of this file, if not already cached. + */ + private void doGetChildren() throws IOException { + if (childMap != null) { + return; + } + + final FtpClient client = getAbstractFileSystem().getClient(); + try { + final String path = ftpFile != null && ftpFile.isSymbolicLink() + ? getFileSystem().getFileSystemManager().resolveName(getParent().getName(), ftpFile.getLink()) + .getPath() + : relPath; + final FTPFile[] tmpChildren = client.listFiles(path); + if (ArrayUtils.isEmpty(tmpChildren)) { + childMap = EMPTY_FTP_FILE_MAP; + } else { + childMap = new TreeMap<>(); + + // Remove '.' and '..' elements + for (int i = 0; i < tmpChildren.length; i++) { + final FTPFile child = tmpChildren[i]; + if (child == null) { + if (log.isDebugEnabled()) { + log.debug(Messages.getString("vfs.provider.ftp/invalid-directory-entry.debug", + Integer.valueOf(i), relPath)); + } + continue; + } + if (!".".equals(child.getName()) && !"..".equals(child.getName())) { + childMap.put(child.getName(), child); + } + } + } + } finally { + getAbstractFileSystem().putClient(client); + } + } + + /** + * Returns the size of the file content (in bytes). + */ + @Override + protected long doGetContentSize() throws Exception { + synchronized (getFileSystem()) { + if (ftpFile == null) { + return 0; + } + if (ftpFile.isSymbolicLink()) { + final FileObject linkDest = getLinkDestination(); + // VFS-437: Try to avoid a recursion loop. + if (isCircular(linkDest)) { + return ftpFile.getSize(); + } + return linkDest.getContent().getSize(); + } + return ftpFile.getSize(); + } + } + + /** + * Creates an input stream to read the file content from. + */ + @Override + protected InputStream doGetInputStream(final int bufferSize) throws Exception { + final FtpClient client = getAbstractFileSystem().getClient(); + try { + final InputStream inputStream = client.retrieveFileStream(relPath, 0); + // VFS-210 + if (inputStream == null) { + throw new FileNotFoundException(getName().toString()); + } + return new FtpInputStream(client, inputStream, bufferSize); + } catch (final Exception e) { + getAbstractFileSystem().putClient(client); + throw e; + } + } + + /** + * Gets the last modified time on an FTP file + * + * @see org.apache.commons.vfs2.provider.AbstractFileObject#doGetLastModifiedTime() + */ + @Override + protected long doGetLastModifiedTime() throws Exception { + synchronized (getFileSystem()) { + if (ftpFile == null) { + return DEFAULT_TIMESTAMP; + } + if (ftpFile.isSymbolicLink()) { + final FileObject linkDest = getLinkDestination(); + // VFS-437: Try to avoid a recursion loop. + if (isCircular(linkDest)) { + return getTimestampMillis(); + } + return linkDest.getContent().getLastModifiedTime(); + } + return getTimestampMillis(); + } + } + + /** + * Creates an output stream to write the file content to. + */ + @Override + protected OutputStream doGetOutputStream(final boolean bAppend) throws Exception { + final FtpClient client = getAbstractFileSystem().getClient(); + try { + final OutputStream out; + if (bAppend) { + out = client.appendFileStream(relPath); + } else { + out = client.storeFileStream(relPath); + } + + FileSystemException.requireNonNull(out, "vfs.provider.ftp/output-error.debug", getName(), + client.getReplyString()); + + return new FtpOutputStream(client, out); + } catch (final Exception e) { + getAbstractFileSystem().putClient(client); + throw e; + } + } + + @Override + protected RandomAccessContent doGetRandomAccessContent(final RandomAccessMode mode) throws Exception { + return new FtpRandomAccessContent(this, mode); + } + + /** + * Determines the type of the file, returns null if the file does not exist. + */ + @Override + protected FileType doGetType() throws Exception { + // VFS-210 + synchronized (getFileSystem()) { + if (ftpFile == null) { + setFTPFile(false); + } + + if (ftpFile == UNKNOWN) { + return FileType.IMAGINARY; + } + if (ftpFile.isDirectory()) { + return FileType.FOLDER; + } + if (ftpFile.isFile()) { + return FileType.FILE; + } + if (ftpFile.isSymbolicLink()) { + final FileObject linkDest = getLinkDestination(); + // VFS-437: We need to check if the symbolic link links back to the symbolic link itself + if (isCircular(linkDest)) { + // If the symbolic link links back to itself, treat it as an imaginary file to prevent following + // this link. If the user tries to access the link as a file or directory, the user will end up with + // a FileSystemException warning that the file cannot be accessed. This is to prevent the infinite + // call back to doGetType() to prevent the StackOverFlow + return FileType.IMAGINARY; + } + return linkDest.getType(); + + } + } + throw new FileSystemException("vfs.provider.ftp/get-type.error", getName()); + } + + /** + * Lists the children of the file. + */ + @Override + protected String[] doListChildren() throws Exception { + // List the children of this file + doGetChildren(); + + // VFS-210 + if (childMap == null) { + return null; + } + + // TODO - get rid of this children stuff + final String[] childNames = childMap.values().stream().filter(Objects::nonNull).map(FTPFile::getName).toArray(String[]::new); + + return UriParser.encode(childNames); + } + + @Override + protected FileObject[] doListChildrenResolved() throws Exception { + synchronized (getFileSystem()) { + if (ftpFile != null && ftpFile.isSymbolicLink()) { + final FileObject linkDest = getLinkDestination(); + // VFS-437: Try to avoid a recursion loop. + if (isCircular(linkDest)) { + return null; + } + return linkDest.getChildren(); + } + } + return null; + } + + /** + * Renames the file + */ + @Override + protected void doRename(final FileObject newFile) throws Exception { + synchronized (getFileSystem()) { + final boolean ok; + final FtpClient ftpClient = getAbstractFileSystem().getClient(); + try { + final String newName = ((FtpFileObject) FileObjectUtils.getAbstractFileObject(newFile)).getRelPath(); + ok = ftpClient.rename(relPath, newName); + } finally { + getAbstractFileSystem().putClient(ftpClient); + } + + if (!ok) { + throw new FileSystemException("vfs.provider.ftp/rename-file.error", getName().toString(), newFile); + } + ftpFile = null; + childMap = EMPTY_FTP_FILE_MAP; + } + } + + /** + * Called by child file objects, to locate their FTP file info. + * + * @param name the file name in its native form i.e. without URI stuff (%nn) + * @param flush recreate children cache + */ + private FTPFile getChildFile(final String name, final boolean flush) throws IOException { + /* + * If we should flush cached children, clear our children map unless we're in the middle of a refresh in which + * case we've just recently refreshed our children. No need to do it again when our children are refresh()ed, + * calling getChildFile() for themselves from within getInfo(). See getChildren(). + */ + if (flush && !inRefresh.get()) { + childMap = null; + } + + // List the children of this file + doGetChildren(); + + // Look for the requested child + // VFS-210 adds the null check. + return childMap != null ? childMap.get(name) : null; + } + + /** + * Returns the file's list of children. + * + * @return The list of children + * @throws FileSystemException If there was a problem listing children + * @see AbstractFileObject#getChildren() + * @since 2.0 + */ + @Override + public FileObject[] getChildren() throws FileSystemException { + try { + if (doGetType() != FileType.FOLDER) { + throw new FileNotFolderException(getName()); + } + } catch (final Exception ex) { + throw new FileNotFolderException(getName(), ex); + } + + try { + /* + * Wrap our parent implementation, noting that we're refreshing so that we don't refresh() ourselves and + * each of our parents for each child. Note that refresh() will list children. Meaning, if this file + * has C children, P parents, there will be (C * P) listings made with (C * (P + 1)) refreshes, when there + * should really only be 1 listing and C refreshes. + */ + inRefresh.set(true); + return super.getChildren(); + } finally { + inRefresh.set(false); + } + } + + FtpInputStream getInputStream(final long filePointer) throws IOException { + final FtpClient client = getAbstractFileSystem().getClient(); + try { + final InputStream instr = client.retrieveFileStream(relPath, filePointer); + FileSystemException.requireNonNull(instr, "vfs.provider.ftp/input-error.debug", getName(), + client.getReplyString()); + return new FtpInputStream(client, instr); + } catch (final IOException e) { + getAbstractFileSystem().putClient(client); + throw e; + } + } + + private FileObject getLinkDestination() throws FileSystemException { + if (linkDestination == null) { + final String path; + synchronized (getFileSystem()) { + path = ftpFile == null ? null : ftpFile.getLink(); + } + final FileName parent = getName().getParent(); + final FileName relativeTo = parent == null ? getName() : parent; + final FileName linkDestinationName = getFileSystem().getFileSystemManager().resolveName(relativeTo, path); + linkDestination = getFileSystem().resolveFile(linkDestinationName); + } + return linkDestination; + } + + String getRelPath() { + return relPath; + } + + /** + * ftpFile is not null. + */ + @SuppressWarnings("resource") // abstractFileSystem is managed in the superclass. + private long getTimestampMillis() throws IOException { + final FtpFileSystem abstractFileSystem = getAbstractFileSystem(); + final Boolean mdtmLastModifiedTime = FtpFileSystemConfigBuilder.getInstance() + .getMdtmLastModifiedTime(abstractFileSystem.getFileSystemOptions()); + if (mdtmLastModifiedTime != null && mdtmLastModifiedTime.booleanValue()) { + final FtpClient client = abstractFileSystem.getClient(); + if (!mdtmSet && client.hasFeature("MDTM")) { + final Instant mdtmInstant = client.mdtmInstant(relPath); + final Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT")); + final long epochMilli = mdtmInstant.toEpochMilli(); + calendar.setTimeInMillis(epochMilli); + ftpFile.setTimestamp(calendar); + mdtmSet = true; + } + } + return ftpFile.getTimestamp().getTime().getTime(); + } + + /** + * This is an over simplistic implementation for VFS-437. + */ + private boolean isCircular(final FileObject linkDest) throws FileSystemException { + return linkDest.getName().getPathDecoded().equals(getName().getPathDecoded()); + } + + /** + * Called when the type or content of this file changes. + */ + @Override + protected void onChange() throws IOException { + childMap = null; + + if (getType().equals(FileType.IMAGINARY)) { + // file is deleted, avoid server lookup + synchronized (getFileSystem()) { + ftpFile = UNKNOWN; + } + return; + } + + setFTPFile(true); + } + + /** + * Called when the children of this file change. + */ + @Override + protected void onChildrenChanged(final FileName child, final FileType newType) { + if (childMap != null && newType.equals(FileType.IMAGINARY)) { + Uncheck.run(() -> childMap.remove(UriParser.decode(child.getBaseName()))); + } else { + // if child was added we have to rescan the children + // TODO - get rid of this + childMap = null; + } + } + + /** + * @throws FileSystemException if an error occurs. + */ + @Override + public void refresh() throws FileSystemException { + if (inRefresh.compareAndSet(false, true)) { + try { + super.refresh(); + synchronized (getFileSystem()) { + ftpFile = null; + } + /* + * VFS-210 try { // this will tell the parent to recreate its children collection getInfo(true); } catch + * (IOException e) { throw new FileSystemException(e); } + */ + } finally { + inRefresh.set(false); + } + } + } + + /** + * Sets the internal FTPFile for this instance. + */ + private void setFTPFile(final boolean flush) throws IOException { + synchronized (getFileSystem()) { + final FtpFileObject parent = (FtpFileObject) FileObjectUtils.getAbstractFileObject(getParent()); + final FTPFile newFileInfo; + if (parent != null) { + newFileInfo = parent.getChildFile(UriParser.decode(getName().getBaseName()), flush); + } else { + // Assume the root is a directory and exists + newFileInfo = new FTPFile(); + newFileInfo.setType(FTPFile.DIRECTORY_TYPE); + } + ftpFile = newFileInfo == null ? UNKNOWN : newFileInfo; + } + } +} diff --git a/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http5/Http5FileProvider.java b/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http5/Http5FileProvider.java index a8fac8147b..31a907228c 100644 --- a/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http5/Http5FileProvider.java +++ b/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http5/Http5FileProvider.java @@ -1,375 +1,375 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.vfs2.provider.http5; - -import java.io.File; -import java.io.IOException; -import java.net.ProxySelector; -import java.security.KeyManagementException; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.cert.CertificateException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Objects; -import java.util.stream.Stream; - -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.SSLContext; - -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.vfs2.Capability; -import org.apache.commons.vfs2.FileName; -import org.apache.commons.vfs2.FileSystem; -import org.apache.commons.vfs2.FileSystemConfigBuilder; -import org.apache.commons.vfs2.FileSystemException; -import org.apache.commons.vfs2.FileSystemOptions; -import org.apache.commons.vfs2.UserAuthenticationData; -import org.apache.commons.vfs2.UserAuthenticator; -import org.apache.commons.vfs2.provider.AbstractOriginatingFileProvider; -import org.apache.commons.vfs2.provider.GenericFileName; -import org.apache.commons.vfs2.util.UserAuthenticatorUtils; -import org.apache.hc.client5.http.auth.AuthCache; -import org.apache.hc.client5.http.auth.AuthScope; -import org.apache.hc.client5.http.auth.UsernamePasswordCredentials; -import org.apache.hc.client5.http.classic.HttpClient; -import org.apache.hc.client5.http.config.ConnectionConfig; -import org.apache.hc.client5.http.cookie.BasicCookieStore; -import org.apache.hc.client5.http.cookie.Cookie; -import org.apache.hc.client5.http.cookie.CookieStore; -import org.apache.hc.client5.http.impl.auth.BasicAuthCache; -import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider; -import org.apache.hc.client5.http.impl.auth.BasicScheme; -import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; -import org.apache.hc.client5.http.impl.classic.HttpClients; -import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder; -import org.apache.hc.client5.http.impl.routing.DefaultProxyRoutePlanner; -import org.apache.hc.client5.http.impl.routing.SystemDefaultRoutePlanner; -import org.apache.hc.client5.http.io.HttpClientConnectionManager; -import org.apache.hc.client5.http.protocol.HttpClientContext; -import org.apache.hc.client5.http.routing.HttpRoutePlanner; -import org.apache.hc.client5.http.ssl.DefaultHostnameVerifier; -import org.apache.hc.client5.http.ssl.NoopHostnameVerifier; -import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; -import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactoryBuilder; -import org.apache.hc.client5.http.ssl.TrustAllStrategy; -import org.apache.hc.core5.http.ConnectionReuseStrategy; -import org.apache.hc.core5.http.Header; -import org.apache.hc.core5.http.HttpHeaders; -import org.apache.hc.core5.http.HttpHost; -import org.apache.hc.core5.http.impl.DefaultConnectionReuseStrategy; -import org.apache.hc.core5.http.io.SocketConfig; -import org.apache.hc.core5.http.message.BasicHeader; -import org.apache.hc.core5.http.ssl.TLS; -import org.apache.hc.core5.ssl.SSLContextBuilder; -import org.apache.hc.core5.util.Timeout; - -/** - * {@code FileProvider} implementation using HttpComponents HttpClient v5 library. - * - * @since 2.5.0 - */ -public class Http5FileProvider extends AbstractOriginatingFileProvider { - - /** Authenticator information. */ - static final UserAuthenticationData.Type[] AUTHENTICATOR_TYPES = - { - UserAuthenticationData.USERNAME, - UserAuthenticationData.PASSWORD - }; - - /** FileProvider capabilities */ - static final Collection CAPABILITIES = - Collections.unmodifiableCollection( - Arrays.asList( - Capability.GET_TYPE, - Capability.READ_CONTENT, - Capability.URI, - Capability.GET_LAST_MODIFIED, - Capability.ATTRIBUTES, - Capability.RANDOM_ACCESS_READ, - Capability.DIRECTORY_READ_CONTENT - ) - ); - - /** - * Constructs a new provider. - */ - public Http5FileProvider() { - setFileNameParser(Http5FileNameParser.getInstance()); - } - - private HttpClientConnectionManager createConnectionManager(final Http5FileSystemConfigBuilder builder, - final FileSystemOptions fileSystemOptions) throws FileSystemException { - - final ConnectionConfig connectionConfig = ConnectionConfig.custom() - .setConnectTimeout(Timeout.of(builder.getSoTimeoutDuration(fileSystemOptions))) - .build(); - - final SocketConfig socketConfig = - SocketConfig - .custom() - .setSoTimeout(Timeout.of(builder.getSoTimeoutDuration(fileSystemOptions))) - .build(); - - final String[] tlsVersions = builder.getTlsVersions(fileSystemOptions).split("\\s*,\\s*"); - - final TLS[] tlsArray = Stream.of(tlsVersions).filter(Objects::nonNull).map(TLS::valueOf).toArray(TLS[]::new); - - final SSLConnectionSocketFactory sslSocketFactory = SSLConnectionSocketFactoryBuilder.create() - .setSslContext(createSSLContext(builder, fileSystemOptions)) - .setHostnameVerifier(createHostnameVerifier(builder, fileSystemOptions)) - .setTlsVersions(tlsArray) - .build(); - - return PoolingHttpClientConnectionManagerBuilder.create() - .setDefaultConnectionConfig(connectionConfig) - .setSSLSocketFactory(sslSocketFactory) - .setMaxConnTotal(builder.getMaxTotalConnections(fileSystemOptions)) - .setMaxConnPerRoute(builder.getMaxConnectionsPerHost(fileSystemOptions)) - .setDefaultSocketConfig(socketConfig) - .build(); - } - - private CookieStore createDefaultCookieStore(final Http5FileSystemConfigBuilder builder, - final FileSystemOptions fileSystemOptions) { - final CookieStore cookieStore = new BasicCookieStore(); - final Cookie[] cookies = builder.getCookies(fileSystemOptions); - - if (cookies != null) { - Stream.of(cookies).forEach(cookieStore::addCookie); - } - - return cookieStore; - } - - private HostnameVerifier createHostnameVerifier(final Http5FileSystemConfigBuilder builder, final FileSystemOptions fileSystemOptions) { - if (!builder.isHostnameVerificationEnabled(fileSystemOptions)) { - return NoopHostnameVerifier.INSTANCE; - } - return new DefaultHostnameVerifier(); - } - - /** - * Create an {@link HttpClient} object for an http4 file system. - * - * @param builder Configuration options builder for http4 provider - * @param rootName The root path - * @param fileSystemOptions The file system options - * @return an {@link HttpClient} object - * @throws FileSystemException if an error occurs. - */ - protected HttpClient createHttpClient(final Http5FileSystemConfigBuilder builder, final GenericFileName rootName, - final FileSystemOptions fileSystemOptions) throws FileSystemException { - return createHttpClientBuilder(builder, rootName, fileSystemOptions).build(); - } - - /** - * Create an {@link HttpClientBuilder} object. Invoked by {@link #createHttpClient(Http5FileSystemConfigBuilder, GenericFileName, FileSystemOptions)}. - * - * @param builder Configuration options builder for HTTP4 provider - * @param rootName The root path - * @param fileSystemOptions The FileSystem options - * @return an {@link HttpClientBuilder} object - * @throws FileSystemException if an error occurs - */ - protected HttpClientBuilder createHttpClientBuilder(final Http5FileSystemConfigBuilder builder, final GenericFileName rootName, - final FileSystemOptions fileSystemOptions) throws FileSystemException { - final List
defaultHeaders = new ArrayList<>(); - defaultHeaders.add(new BasicHeader(HttpHeaders.USER_AGENT, builder.getUserAgent(fileSystemOptions))); - - final ConnectionReuseStrategy connectionReuseStrategy = builder.isKeepAlive(fileSystemOptions) - ? DefaultConnectionReuseStrategy.INSTANCE - : (request, response, context) -> false; - - final HttpClientBuilder httpClientBuilder = - HttpClients.custom() - .setRoutePlanner(createHttpRoutePlanner(builder, fileSystemOptions)) - .setConnectionManager(createConnectionManager(builder, fileSystemOptions)) - .setConnectionReuseStrategy(connectionReuseStrategy) - .setDefaultHeaders(defaultHeaders) - .setDefaultCookieStore(createDefaultCookieStore(builder, fileSystemOptions)); - - if (!builder.getFollowRedirect(fileSystemOptions)) { - httpClientBuilder.disableRedirectHandling(); - } - - return httpClientBuilder; - } - - /** - * Create an {@link HttpClientContext} object for an http4 file system. - * - * @param builder Configuration options builder for http4 provider - * @param rootName The root path - * @param fileSystemOptions The FileSystem options - * @param authData The {@code UserAuthenticationData} object - * @return an {@link HttpClientContext} object - */ - protected HttpClientContext createHttpClientContext(final Http5FileSystemConfigBuilder builder, - final GenericFileName rootName, final FileSystemOptions fileSystemOptions, - final UserAuthenticationData authData) { - - final HttpClientContext clientContext = HttpClientContext.create(); - final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider(); - clientContext.setCredentialsProvider(credsProvider); - - final String username = UserAuthenticatorUtils.toString(UserAuthenticatorUtils.getData(authData, - UserAuthenticationData.USERNAME, UserAuthenticatorUtils.toChar(rootName.getUserName()))); - final char[] password = UserAuthenticatorUtils.getData(authData, - UserAuthenticationData.PASSWORD, UserAuthenticatorUtils.toChar(rootName.getPassword())); - - if (!StringUtils.isEmpty(username)) { - // set root port - credsProvider.setCredentials(new AuthScope(rootName.getHostName(), rootName.getPort()), - new UsernamePasswordCredentials(username, password)); - } - - final HttpHost proxyHost = getProxyHttpHost(builder, fileSystemOptions); - - if (proxyHost != null) { - final UserAuthenticator proxyAuth = builder.getProxyAuthenticator(fileSystemOptions); - - if (proxyAuth != null) { - final UserAuthenticationData proxyAuthData = UserAuthenticatorUtils.authenticate(proxyAuth, - new UserAuthenticationData.Type[] {UserAuthenticationData.USERNAME, UserAuthenticationData.PASSWORD}); - - if (proxyAuthData != null) { - final UsernamePasswordCredentials proxyCreds = new UsernamePasswordCredentials( - UserAuthenticatorUtils.toString( - UserAuthenticatorUtils.getData(proxyAuthData, UserAuthenticationData.USERNAME, null)), - UserAuthenticatorUtils.getData(proxyAuthData, UserAuthenticationData.PASSWORD, null)); - - // set proxy host port - credsProvider.setCredentials(new AuthScope(proxyHost.getHostName(), proxyHost.getPort()), - proxyCreds); - } - - if (builder.isPreemptiveAuth(fileSystemOptions)) { - final AuthCache authCache = new BasicAuthCache(); - final BasicScheme basicAuth = new BasicScheme(); - authCache.put(proxyHost, basicAuth); - clientContext.setAuthCache(authCache); - } - } - } - - return clientContext; - } - - private HttpRoutePlanner createHttpRoutePlanner(final Http5FileSystemConfigBuilder builder, - final FileSystemOptions fileSystemOptions) { - final HttpHost proxyHost = getProxyHttpHost(builder, fileSystemOptions); - - if (proxyHost != null) { - return new DefaultProxyRoutePlanner(proxyHost); - } - - return new SystemDefaultRoutePlanner(ProxySelector.getDefault()); - } - - /** - * Create {@link SSLContext} for HttpClient. Invoked by {@link #createHttpClientBuilder(Http5FileSystemConfigBuilder, GenericFileName, FileSystemOptions)}. - * - * @param builder Configuration options builder for HTTP4 provider - * @param fileSystemOptions The FileSystem options - * @return a {@link SSLContext} for HttpClient - * @throws FileSystemException if an error occurs - */ - protected SSLContext createSSLContext(final Http5FileSystemConfigBuilder builder, - final FileSystemOptions fileSystemOptions) throws FileSystemException { - try { - final SSLContextBuilder sslContextBuilder = new SSLContextBuilder(); - sslContextBuilder.setKeyStoreType(builder.getKeyStoreType(fileSystemOptions)); - - File keystoreFileObject = null; - final String keystoreFile = builder.getKeyStoreFile(fileSystemOptions); - - if (!StringUtils.isEmpty(keystoreFile)) { - keystoreFileObject = new File(keystoreFile); - } - - if (keystoreFileObject != null && keystoreFileObject.exists()) { - final String keystorePass = builder.getKeyStorePass(fileSystemOptions); - final char[] keystorePassChars = keystorePass != null ? keystorePass.toCharArray() : null; - sslContextBuilder.loadTrustMaterial(keystoreFileObject, keystorePassChars, TrustAllStrategy.INSTANCE); - } else { - sslContextBuilder.loadTrustMaterial(TrustAllStrategy.INSTANCE); - } - - return sslContextBuilder.build(); - } catch (final KeyStoreException e) { - throw new FileSystemException("Keystore error. " + e.getMessage(), e); - } catch (final KeyManagementException e) { - throw new FileSystemException("Cannot retrieve keys. " + e.getMessage(), e); - } catch (final NoSuchAlgorithmException e) { - throw new FileSystemException("Algorithm error. " + e.getMessage(), e); - } catch (final CertificateException e) { - throw new FileSystemException("Certificate error. " + e.getMessage(), e); - } catch (final IOException e) { - throw new FileSystemException("Cannot open key file. " + e.getMessage(), e); - } - } - - @Override - protected FileSystem doCreateFileSystem(final FileName name, final FileSystemOptions fileSystemOptions) - throws FileSystemException { - final GenericFileName rootName = (GenericFileName) name; - - UserAuthenticationData authData = null; - HttpClient httpClient; - HttpClientContext httpClientContext; - - try { - final Http5FileSystemConfigBuilder builder = Http5FileSystemConfigBuilder.getInstance(); - authData = UserAuthenticatorUtils.authenticate(fileSystemOptions, AUTHENTICATOR_TYPES); - httpClientContext = createHttpClientContext(builder, rootName, fileSystemOptions, authData); - httpClient = createHttpClient(builder, rootName, fileSystemOptions); - } finally { - UserAuthenticatorUtils.cleanup(authData); - } - - return new Http5FileSystem(rootName, fileSystemOptions, httpClient, httpClientContext); - } - - @Override - public Collection getCapabilities() { - return CAPABILITIES; - } - - @Override - public FileSystemConfigBuilder getConfigBuilder() { - return Http5FileSystemConfigBuilder.getInstance(); - } - - private HttpHost getProxyHttpHost(final Http5FileSystemConfigBuilder builder, - final FileSystemOptions fileSystemOptions) { - final String proxyScheme = builder.getProxyScheme(fileSystemOptions); - final String proxyHost = builder.getProxyHost(fileSystemOptions); - final int proxyPort = builder.getProxyPort(fileSystemOptions); - - if (!StringUtils.isEmpty(proxyHost) && proxyPort > 0) { - return new HttpHost(proxyScheme, proxyHost, proxyPort); - } - - return null; - } - -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.vfs2.provider.http5; + +import java.io.File; +import java.io.IOException; +import java.net.ProxySelector; +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.stream.Stream; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLContext; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.vfs2.Capability; +import org.apache.commons.vfs2.FileName; +import org.apache.commons.vfs2.FileSystem; +import org.apache.commons.vfs2.FileSystemConfigBuilder; +import org.apache.commons.vfs2.FileSystemException; +import org.apache.commons.vfs2.FileSystemOptions; +import org.apache.commons.vfs2.UserAuthenticationData; +import org.apache.commons.vfs2.UserAuthenticator; +import org.apache.commons.vfs2.provider.AbstractOriginatingFileProvider; +import org.apache.commons.vfs2.provider.GenericFileName; +import org.apache.commons.vfs2.util.UserAuthenticatorUtils; +import org.apache.hc.client5.http.auth.AuthCache; +import org.apache.hc.client5.http.auth.AuthScope; +import org.apache.hc.client5.http.auth.UsernamePasswordCredentials; +import org.apache.hc.client5.http.classic.HttpClient; +import org.apache.hc.client5.http.config.ConnectionConfig; +import org.apache.hc.client5.http.cookie.BasicCookieStore; +import org.apache.hc.client5.http.cookie.Cookie; +import org.apache.hc.client5.http.cookie.CookieStore; +import org.apache.hc.client5.http.impl.auth.BasicAuthCache; +import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider; +import org.apache.hc.client5.http.impl.auth.BasicScheme; +import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder; +import org.apache.hc.client5.http.impl.routing.DefaultProxyRoutePlanner; +import org.apache.hc.client5.http.impl.routing.SystemDefaultRoutePlanner; +import org.apache.hc.client5.http.io.HttpClientConnectionManager; +import org.apache.hc.client5.http.protocol.HttpClientContext; +import org.apache.hc.client5.http.routing.HttpRoutePlanner; +import org.apache.hc.client5.http.ssl.DefaultHostnameVerifier; +import org.apache.hc.client5.http.ssl.NoopHostnameVerifier; +import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; +import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactoryBuilder; +import org.apache.hc.client5.http.ssl.TrustAllStrategy; +import org.apache.hc.core5.http.ConnectionReuseStrategy; +import org.apache.hc.core5.http.Header; +import org.apache.hc.core5.http.HttpHeaders; +import org.apache.hc.core5.http.HttpHost; +import org.apache.hc.core5.http.impl.DefaultConnectionReuseStrategy; +import org.apache.hc.core5.http.io.SocketConfig; +import org.apache.hc.core5.http.message.BasicHeader; +import org.apache.hc.core5.http.ssl.TLS; +import org.apache.hc.core5.ssl.SSLContextBuilder; +import org.apache.hc.core5.util.Timeout; + +/** + * {@code FileProvider} implementation using HttpComponents HttpClient v5 library. + * + * @since 2.5.0 + */ +public class Http5FileProvider extends AbstractOriginatingFileProvider { + + /** Authenticator information. */ + static final UserAuthenticationData.Type[] AUTHENTICATOR_TYPES = + { + UserAuthenticationData.USERNAME, + UserAuthenticationData.PASSWORD + }; + + /** FileProvider capabilities */ + static final Collection CAPABILITIES = + Collections.unmodifiableCollection( + Arrays.asList( + Capability.GET_TYPE, + Capability.READ_CONTENT, + Capability.URI, + Capability.GET_LAST_MODIFIED, + Capability.ATTRIBUTES, + Capability.RANDOM_ACCESS_READ, + Capability.DIRECTORY_READ_CONTENT + ) + ); + + /** + * Constructs a new provider. + */ + public Http5FileProvider() { + setFileNameParser(Http5FileNameParser.getInstance()); + } + + private HttpClientConnectionManager createConnectionManager(final Http5FileSystemConfigBuilder builder, + final FileSystemOptions fileSystemOptions) throws FileSystemException { + + final ConnectionConfig connectionConfig = ConnectionConfig.custom() + .setConnectTimeout(Timeout.of(builder.getSoTimeoutDuration(fileSystemOptions))) + .build(); + + final SocketConfig socketConfig = + SocketConfig + .custom() + .setSoTimeout(Timeout.of(builder.getSoTimeoutDuration(fileSystemOptions))) + .build(); + + final String[] tlsVersions = builder.getTlsVersions(fileSystemOptions).split("\\s*,\\s*"); + + final TLS[] tlsArray = Stream.of(tlsVersions).filter(Objects::nonNull).map(TLS::valueOf).toArray(TLS[]::new); + + final SSLConnectionSocketFactory sslSocketFactory = SSLConnectionSocketFactoryBuilder.create() + .setSslContext(createSSLContext(builder, fileSystemOptions)) + .setHostnameVerifier(createHostnameVerifier(builder, fileSystemOptions)) + .setTlsVersions(tlsArray) + .build(); + + return PoolingHttpClientConnectionManagerBuilder.create() + .setDefaultConnectionConfig(connectionConfig) + .setSSLSocketFactory(sslSocketFactory) + .setMaxConnTotal(builder.getMaxTotalConnections(fileSystemOptions)) + .setMaxConnPerRoute(builder.getMaxConnectionsPerHost(fileSystemOptions)) + .setDefaultSocketConfig(socketConfig) + .build(); + } + + private CookieStore createDefaultCookieStore(final Http5FileSystemConfigBuilder builder, + final FileSystemOptions fileSystemOptions) { + final CookieStore cookieStore = new BasicCookieStore(); + final Cookie[] cookies = builder.getCookies(fileSystemOptions); + + if (cookies != null) { + Stream.of(cookies).forEach(cookieStore::addCookie); + } + + return cookieStore; + } + + private HostnameVerifier createHostnameVerifier(final Http5FileSystemConfigBuilder builder, final FileSystemOptions fileSystemOptions) { + if (!builder.isHostnameVerificationEnabled(fileSystemOptions)) { + return NoopHostnameVerifier.INSTANCE; + } + return new DefaultHostnameVerifier(); + } + + /** + * Create an {@link HttpClient} object for an http4 file system. + * + * @param builder Configuration options builder for http4 provider + * @param rootName The root path + * @param fileSystemOptions The file system options + * @return an {@link HttpClient} object + * @throws FileSystemException if an error occurs. + */ + protected HttpClient createHttpClient(final Http5FileSystemConfigBuilder builder, final GenericFileName rootName, + final FileSystemOptions fileSystemOptions) throws FileSystemException { + return createHttpClientBuilder(builder, rootName, fileSystemOptions).build(); + } + + /** + * Create an {@link HttpClientBuilder} object. Invoked by {@link #createHttpClient(Http5FileSystemConfigBuilder, GenericFileName, FileSystemOptions)}. + * + * @param builder Configuration options builder for HTTP4 provider + * @param rootName The root path + * @param fileSystemOptions The FileSystem options + * @return an {@link HttpClientBuilder} object + * @throws FileSystemException if an error occurs + */ + protected HttpClientBuilder createHttpClientBuilder(final Http5FileSystemConfigBuilder builder, final GenericFileName rootName, + final FileSystemOptions fileSystemOptions) throws FileSystemException { + final List
defaultHeaders = new ArrayList<>(); + defaultHeaders.add(new BasicHeader(HttpHeaders.USER_AGENT, builder.getUserAgent(fileSystemOptions))); + + final ConnectionReuseStrategy connectionReuseStrategy = builder.isKeepAlive(fileSystemOptions) + ? DefaultConnectionReuseStrategy.INSTANCE + : (request, response, context) -> false; + + final HttpClientBuilder httpClientBuilder = + HttpClients.custom() + .setRoutePlanner(createHttpRoutePlanner(builder, fileSystemOptions)) + .setConnectionManager(createConnectionManager(builder, fileSystemOptions)) + .setConnectionReuseStrategy(connectionReuseStrategy) + .setDefaultHeaders(defaultHeaders) + .setDefaultCookieStore(createDefaultCookieStore(builder, fileSystemOptions)); + + if (!builder.getFollowRedirect(fileSystemOptions)) { + httpClientBuilder.disableRedirectHandling(); + } + + return httpClientBuilder; + } + + /** + * Create an {@link HttpClientContext} object for an http4 file system. + * + * @param builder Configuration options builder for http4 provider + * @param rootName The root path + * @param fileSystemOptions The FileSystem options + * @param authData The {@code UserAuthenticationData} object + * @return an {@link HttpClientContext} object + */ + protected HttpClientContext createHttpClientContext(final Http5FileSystemConfigBuilder builder, + final GenericFileName rootName, final FileSystemOptions fileSystemOptions, + final UserAuthenticationData authData) { + + final HttpClientContext clientContext = HttpClientContext.create(); + final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider(); + clientContext.setCredentialsProvider(credsProvider); + + final String username = UserAuthenticatorUtils.toString(UserAuthenticatorUtils.getData(authData, + UserAuthenticationData.USERNAME, UserAuthenticatorUtils.toChar(rootName.getUserName()))); + final char[] password = UserAuthenticatorUtils.getData(authData, + UserAuthenticationData.PASSWORD, UserAuthenticatorUtils.toChar(rootName.getPassword())); + + if (!StringUtils.isEmpty(username)) { + // set root port + credsProvider.setCredentials(new AuthScope(rootName.getHostName(), rootName.getPort()), + new UsernamePasswordCredentials(username, password)); + } + + final HttpHost proxyHost = getProxyHttpHost(builder, fileSystemOptions); + + if (proxyHost != null) { + final UserAuthenticator proxyAuth = builder.getProxyAuthenticator(fileSystemOptions); + + if (proxyAuth != null) { + final UserAuthenticationData proxyAuthData = UserAuthenticatorUtils.authenticate(proxyAuth, + new UserAuthenticationData.Type[] {UserAuthenticationData.USERNAME, UserAuthenticationData.PASSWORD}); + + if (proxyAuthData != null) { + final UsernamePasswordCredentials proxyCreds = new UsernamePasswordCredentials( + UserAuthenticatorUtils.toString( + UserAuthenticatorUtils.getData(proxyAuthData, UserAuthenticationData.USERNAME, null)), + UserAuthenticatorUtils.getData(proxyAuthData, UserAuthenticationData.PASSWORD, null)); + + // set proxy host port + credsProvider.setCredentials(new AuthScope(proxyHost.getHostName(), proxyHost.getPort()), + proxyCreds); + } + + if (builder.isPreemptiveAuth(fileSystemOptions)) { + final AuthCache authCache = new BasicAuthCache(); + final BasicScheme basicAuth = new BasicScheme(); + authCache.put(proxyHost, basicAuth); + clientContext.setAuthCache(authCache); + } + } + } + + return clientContext; + } + + private HttpRoutePlanner createHttpRoutePlanner(final Http5FileSystemConfigBuilder builder, + final FileSystemOptions fileSystemOptions) { + final HttpHost proxyHost = getProxyHttpHost(builder, fileSystemOptions); + + if (proxyHost != null) { + return new DefaultProxyRoutePlanner(proxyHost); + } + + return new SystemDefaultRoutePlanner(ProxySelector.getDefault()); + } + + /** + * Create {@link SSLContext} for HttpClient. Invoked by {@link #createHttpClientBuilder(Http5FileSystemConfigBuilder, GenericFileName, FileSystemOptions)}. + * + * @param builder Configuration options builder for HTTP4 provider + * @param fileSystemOptions The FileSystem options + * @return a {@link SSLContext} for HttpClient + * @throws FileSystemException if an error occurs + */ + protected SSLContext createSSLContext(final Http5FileSystemConfigBuilder builder, + final FileSystemOptions fileSystemOptions) throws FileSystemException { + try { + final SSLContextBuilder sslContextBuilder = new SSLContextBuilder(); + sslContextBuilder.setKeyStoreType(builder.getKeyStoreType(fileSystemOptions)); + + File keystoreFileObject = null; + final String keystoreFile = builder.getKeyStoreFile(fileSystemOptions); + + if (!StringUtils.isEmpty(keystoreFile)) { + keystoreFileObject = new File(keystoreFile); + } + + if (keystoreFileObject != null && keystoreFileObject.exists()) { + final String keystorePass = builder.getKeyStorePass(fileSystemOptions); + final char[] keystorePassChars = keystorePass != null ? keystorePass.toCharArray() : null; + sslContextBuilder.loadTrustMaterial(keystoreFileObject, keystorePassChars, TrustAllStrategy.INSTANCE); + } else { + sslContextBuilder.loadTrustMaterial(TrustAllStrategy.INSTANCE); + } + + return sslContextBuilder.build(); + } catch (final KeyStoreException e) { + throw new FileSystemException("Keystore error. " + e.getMessage(), e); + } catch (final KeyManagementException e) { + throw new FileSystemException("Cannot retrieve keys. " + e.getMessage(), e); + } catch (final NoSuchAlgorithmException e) { + throw new FileSystemException("Algorithm error. " + e.getMessage(), e); + } catch (final CertificateException e) { + throw new FileSystemException("Certificate error. " + e.getMessage(), e); + } catch (final IOException e) { + throw new FileSystemException("Cannot open key file. " + e.getMessage(), e); + } + } + + @Override + protected FileSystem doCreateFileSystem(final FileName name, final FileSystemOptions fileSystemOptions) + throws FileSystemException { + final GenericFileName rootName = (GenericFileName) name; + + UserAuthenticationData authData = null; + HttpClient httpClient; + HttpClientContext httpClientContext; + + try { + final Http5FileSystemConfigBuilder builder = Http5FileSystemConfigBuilder.getInstance(); + authData = UserAuthenticatorUtils.authenticate(fileSystemOptions, AUTHENTICATOR_TYPES); + httpClientContext = createHttpClientContext(builder, rootName, fileSystemOptions, authData); + httpClient = createHttpClient(builder, rootName, fileSystemOptions); + } finally { + UserAuthenticatorUtils.cleanup(authData); + } + + return new Http5FileSystem(rootName, fileSystemOptions, httpClient, httpClientContext); + } + + @Override + public Collection getCapabilities() { + return CAPABILITIES; + } + + @Override + public FileSystemConfigBuilder getConfigBuilder() { + return Http5FileSystemConfigBuilder.getInstance(); + } + + private HttpHost getProxyHttpHost(final Http5FileSystemConfigBuilder builder, + final FileSystemOptions fileSystemOptions) { + final String proxyScheme = builder.getProxyScheme(fileSystemOptions); + final String proxyHost = builder.getProxyHost(fileSystemOptions); + final int proxyPort = builder.getProxyPort(fileSystemOptions); + + if (!StringUtils.isEmpty(proxyHost) && proxyPort > 0) { + return new HttpHost(proxyScheme, proxyHost, proxyPort); + } + + return null; + } + +} diff --git a/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/local/WindowsFileNameParser.java b/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/local/WindowsFileNameParser.java index b947654120..038c8f2892 100644 --- a/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/local/WindowsFileNameParser.java +++ b/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/local/WindowsFileNameParser.java @@ -1,143 +1,143 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.vfs2.provider.local; - -import org.apache.commons.vfs2.FileName; -import org.apache.commons.vfs2.FileSystemException; -import org.apache.commons.vfs2.FileType; - -/** - * A parser for Windows file names. - */ -public class WindowsFileNameParser extends LocalFileNameParser { - - /** - * Constructs a new instance. - */ - public WindowsFileNameParser() { - // empty - } - - @Override - protected FileName createFileName(final String scheme, final String rootFile, final String path, - final FileType type) { - return new WindowsFileName(scheme, rootFile, path, type); - } - - /** - * Extracts a drive prefix from a path. Leading '/' chars have been removed. - */ - private String extractDrivePrefix(final StringBuilder name) { - // Looking for ':' '/' - if (name.length() < 3) { - // Too short - return null; - } - final char ch = name.charAt(0); - if (ch == '/' || ch == ':') { - // Missing drive letter - return null; - } - if (name.charAt(1) != ':') { - // Missing ':' - return null; - } - if (name.charAt(2) != '/') { - // Missing separator - return null; - } - - final String prefix = name.substring(0, 2); - name.delete(0, 2); - - return prefix.intern(); - } - - /** - * Pops the root prefix off a URI, which has had the scheme removed. - */ - @Override - protected String extractRootPrefix(final String uri, final StringBuilder name) throws FileSystemException { - return extractWindowsRootPrefix(uri, name); - } - - /** - * Extracts a UNC name from a path. Leading '/' chars have been removed. - */ - private String extractUNCPrefix(final String uri, final StringBuilder name) throws FileSystemException { - // Looking for '/' ( '/' | ) - - // Look for first separator - final int maxpos = name.length(); - int pos = 0; - while (pos < maxpos && name.charAt(pos) != '/') { - pos++; - } - pos++; - if (pos >= maxpos) { - throw new FileSystemException("vfs.provider.local/missing-share-name.error", uri); - } - - // Now have '/' - final int startShareName = pos; - while (pos < maxpos && name.charAt(pos) != '/') { - pos++; - } - if (pos == startShareName) { - throw new FileSystemException("vfs.provider.local/missing-share-name.error", uri); - } - - // Now have '/' ( '/' | ) - final String prefix = name.substring(0, pos); - name.delete(0, pos); - return prefix; - } - - /** - * Extracts a Windows root prefix from a name. - */ - private String extractWindowsRootPrefix(final String uri, final StringBuilder name) throws FileSystemException { - // Looking for: - // ('/'){0, 3} ':' '/' - // ['/'] '//' '/' ( '/' | ) - - // Skip over first 4 (unc) leading '/' chars - int startPos = 0; - final int maxlen = Math.min(4, name.length()); - while (startPos < maxlen && name.charAt(startPos) == '/') { - startPos++; - } - if (startPos == maxlen && name.length() > startPos + 1 && name.charAt(startPos + 1) == '/') { - // Too many '/' - throw new FileSystemException("vfs.provider.local/not-absolute-file-name.error", uri); - } - name.delete(0, startPos); - - // Look for drive name - final String driveName = extractDrivePrefix(name); - if (driveName != null) { - return driveName; - } - - // Look for UNC name - if (startPos < 2) { - throw new FileSystemException("vfs.provider.local/not-absolute-file-name.error", uri); - } - - return "//" + extractUNCPrefix(uri, name); - } -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.vfs2.provider.local; + +import org.apache.commons.vfs2.FileName; +import org.apache.commons.vfs2.FileSystemException; +import org.apache.commons.vfs2.FileType; + +/** + * A parser for Windows file names. + */ +public class WindowsFileNameParser extends LocalFileNameParser { + + /** + * Constructs a new instance. + */ + public WindowsFileNameParser() { + // empty + } + + @Override + protected FileName createFileName(final String scheme, final String rootFile, final String path, + final FileType type) { + return new WindowsFileName(scheme, rootFile, path, type); + } + + /** + * Extracts a drive prefix from a path. Leading '/' chars have been removed. + */ + private String extractDrivePrefix(final StringBuilder name) { + // Looking for ':' '/' + if (name.length() < 3) { + // Too short + return null; + } + final char ch = name.charAt(0); + if (ch == '/' || ch == ':') { + // Missing drive letter + return null; + } + if (name.charAt(1) != ':') { + // Missing ':' + return null; + } + if (name.charAt(2) != '/') { + // Missing separator + return null; + } + + final String prefix = name.substring(0, 2); + name.delete(0, 2); + + return prefix.intern(); + } + + /** + * Pops the root prefix off a URI, which has had the scheme removed. + */ + @Override + protected String extractRootPrefix(final String uri, final StringBuilder name) throws FileSystemException { + return extractWindowsRootPrefix(uri, name); + } + + /** + * Extracts a UNC name from a path. Leading '/' chars have been removed. + */ + private String extractUNCPrefix(final String uri, final StringBuilder name) throws FileSystemException { + // Looking for '/' ( '/' | ) + + // Look for first separator + final int maxpos = name.length(); + int pos = 0; + while (pos < maxpos && name.charAt(pos) != '/') { + pos++; + } + pos++; + if (pos >= maxpos) { + throw new FileSystemException("vfs.provider.local/missing-share-name.error", uri); + } + + // Now have '/' + final int startShareName = pos; + while (pos < maxpos && name.charAt(pos) != '/') { + pos++; + } + if (pos == startShareName) { + throw new FileSystemException("vfs.provider.local/missing-share-name.error", uri); + } + + // Now have '/' ( '/' | ) + final String prefix = name.substring(0, pos); + name.delete(0, pos); + return prefix; + } + + /** + * Extracts a Windows root prefix from a name. + */ + private String extractWindowsRootPrefix(final String uri, final StringBuilder name) throws FileSystemException { + // Looking for: + // ('/'){0, 3} ':' '/' + // ['/'] '//' '/' ( '/' | ) + + // Skip over first 4 (unc) leading '/' chars + int startPos = 0; + final int maxlen = Math.min(4, name.length()); + while (startPos < maxlen && name.charAt(startPos) == '/') { + startPos++; + } + if (startPos == maxlen && name.length() > startPos + 1 && name.charAt(startPos + 1) == '/') { + // Too many '/' + throw new FileSystemException("vfs.provider.local/not-absolute-file-name.error", uri); + } + name.delete(0, startPos); + + // Look for drive name + final String driveName = extractDrivePrefix(name); + if (driveName != null) { + return driveName; + } + + // Look for UNC name + if (startPos < 2) { + throw new FileSystemException("vfs.provider.local/not-absolute-file-name.error", uri); + } + + return "//" + extractUNCPrefix(uri, name); + } +} diff --git a/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/ram/RamFileData.java b/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/ram/RamFileData.java index ecc8ae4692..194a6eb66b 100644 --- a/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/ram/RamFileData.java +++ b/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/ram/RamFileData.java @@ -1,257 +1,257 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.vfs2.provider.ram; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; - -import org.apache.commons.lang3.ArrayUtils; -import org.apache.commons.vfs2.FileName; -import org.apache.commons.vfs2.FileSystemException; -import org.apache.commons.vfs2.FileType; - -/** - * RAM File Object Data. - */ -final class RamFileData implements Serializable { - - /** - * serialVersionUID format is YYYYMMDD for the date of the last binary change. - */ - private static final long serialVersionUID = 20101208L; - - /** - * File Name. - */ - private FileName name; - - /** - * File Type. - */ - private FileType type; - - /** - * Bytes. - */ - private byte[] content; - - /** - * Last modified time - */ - private long lastModifiedMillis; - - /** - * Children - */ - private final Collection children; - - /** - * Constructs a new instance. - * - * @param name The file name. - */ - RamFileData(final FileName name) { - children = Collections.synchronizedCollection(new ArrayList<>()); - clear(); - if (name == null) { - throw new IllegalArgumentException("name cannot be null"); - } - this.name = name; - } - - /** - * Add a child. - * - * @param data The file data. - * @throws FileSystemException if an error occurs. - */ - void addChild(final RamFileData data) throws FileSystemException { - if (!getType().hasChildren()) { - throw new FileSystemException("A child can only be added in a folder"); - } - - FileSystemException.requireNonNull(data, "No child can be null"); - - if (children.contains(data)) { - throw new FileSystemException("Child already exists. " + data); - } - - children.add(data); - updateLastModified(); - } - - /** - */ - void clear() { - content = ArrayUtils.EMPTY_BYTE_ARRAY; - updateLastModified(); - type = FileType.IMAGINARY; - children.clear(); - name = null; - } - - /* - * (non-Javadoc) - * - * @see Object#equals(Object) - */ - @Override - public boolean equals(final Object o) { - if (this == o) { - return true; - } - if (!(o instanceof RamFileData)) { - return false; - } - final RamFileData data = (RamFileData) o; - return getName().equals(data.getName()); - } - - /** - * @return Returns the children. - */ - Collection getChildren() { - if (name == null) { - throw new IllegalStateException("Data is clear"); - } - return children; - } - - /** - * @return Returns the buffer. - */ - byte[] getContent() { - return content; - } - - /** - * @return Returns the lastModified. - */ - long getLastModified() { - return lastModifiedMillis; - } - - /** - * @return Returns the name. - */ - FileName getName() { - return name; - } - - /** - * @return Returns the type. - */ - FileType getType() { - return type; - } - - boolean hasChildren(final RamFileData data) { - return children.contains(data); - } - - /* - * (non-Javadoc) - * - * @see Object#hashCode() - */ - @Override - public int hashCode() { - return getName().hashCode(); - } - - /** - * Remove a child. - * - * @param data The file data. - * @throws FileSystemException if an error occurs. - */ - void removeChild(final RamFileData data) throws FileSystemException { - if (!getType().hasChildren()) { - throw new FileSystemException("A child can only be removed from a folder"); - } - if (!children.contains(data)) { - throw new FileSystemException("Child not found. " + data); - } - children.remove(data); - updateLastModified(); - } - - /** - * Resize the buffer - * - * @param newSize The new buffer size. - */ - void resize(final long newSize) { - // A future implementation may allow longs/multiple buffer/and so on - if (newSize > Integer.MAX_VALUE) { - throw new IllegalArgumentException( - String.format("newSize(%d) > Integer.MAX_VALUE(%d)", newSize, Integer.MAX_VALUE)); - } - final int resize = (int) newSize; - final int size = size(); - final byte[] newBuf = new byte[resize]; - System.arraycopy(content, 0, newBuf, 0, Math.min(resize, size)); - content = newBuf; - updateLastModified(); - } - - /** - * @param content The buffer. - */ - void setContent(final byte[] content) { - updateLastModified(); - this.content = content; - } - - /** - * @param lastModifiedMillis The lastModified to set. - */ - void setLastModified(final long lastModifiedMillis) { - this.lastModifiedMillis = lastModifiedMillis; - } - - /** - * @param type The type to set. - */ - void setType(final FileType type) { - this.type = type; - } - - /** - * @return Returns the size of the buffer - */ - int size() { - return content.length; - } - - /* - * (non-Javadoc) - * - * @see Object#toString() - */ - @Override - public String toString() { - return name.toString(); - } - - void updateLastModified() { - lastModifiedMillis = System.currentTimeMillis(); - } - -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.vfs2.provider.ram; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; + +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.vfs2.FileName; +import org.apache.commons.vfs2.FileSystemException; +import org.apache.commons.vfs2.FileType; + +/** + * RAM File Object Data. + */ +final class RamFileData implements Serializable { + + /** + * serialVersionUID format is YYYYMMDD for the date of the last binary change. + */ + private static final long serialVersionUID = 20101208L; + + /** + * File Name. + */ + private FileName name; + + /** + * File Type. + */ + private FileType type; + + /** + * Bytes. + */ + private byte[] content; + + /** + * Last modified time + */ + private long lastModifiedMillis; + + /** + * Children + */ + private final Collection children; + + /** + * Constructs a new instance. + * + * @param name The file name. + */ + RamFileData(final FileName name) { + children = Collections.synchronizedCollection(new ArrayList<>()); + clear(); + if (name == null) { + throw new IllegalArgumentException("name cannot be null"); + } + this.name = name; + } + + /** + * Add a child. + * + * @param data The file data. + * @throws FileSystemException if an error occurs. + */ + void addChild(final RamFileData data) throws FileSystemException { + if (!getType().hasChildren()) { + throw new FileSystemException("A child can only be added in a folder"); + } + + FileSystemException.requireNonNull(data, "No child can be null"); + + if (children.contains(data)) { + throw new FileSystemException("Child already exists. " + data); + } + + children.add(data); + updateLastModified(); + } + + /** + */ + void clear() { + content = ArrayUtils.EMPTY_BYTE_ARRAY; + updateLastModified(); + type = FileType.IMAGINARY; + children.clear(); + name = null; + } + + /* + * (non-Javadoc) + * + * @see Object#equals(Object) + */ + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (!(o instanceof RamFileData)) { + return false; + } + final RamFileData data = (RamFileData) o; + return getName().equals(data.getName()); + } + + /** + * @return Returns the children. + */ + Collection getChildren() { + if (name == null) { + throw new IllegalStateException("Data is clear"); + } + return children; + } + + /** + * @return Returns the buffer. + */ + byte[] getContent() { + return content; + } + + /** + * @return Returns the lastModified. + */ + long getLastModified() { + return lastModifiedMillis; + } + + /** + * @return Returns the name. + */ + FileName getName() { + return name; + } + + /** + * @return Returns the type. + */ + FileType getType() { + return type; + } + + boolean hasChildren(final RamFileData data) { + return children.contains(data); + } + + /* + * (non-Javadoc) + * + * @see Object#hashCode() + */ + @Override + public int hashCode() { + return getName().hashCode(); + } + + /** + * Remove a child. + * + * @param data The file data. + * @throws FileSystemException if an error occurs. + */ + void removeChild(final RamFileData data) throws FileSystemException { + if (!getType().hasChildren()) { + throw new FileSystemException("A child can only be removed from a folder"); + } + if (!children.contains(data)) { + throw new FileSystemException("Child not found. " + data); + } + children.remove(data); + updateLastModified(); + } + + /** + * Resize the buffer + * + * @param newSize The new buffer size. + */ + void resize(final long newSize) { + // A future implementation may allow longs/multiple buffer/and so on + if (newSize > Integer.MAX_VALUE) { + throw new IllegalArgumentException( + String.format("newSize(%d) > Integer.MAX_VALUE(%d)", newSize, Integer.MAX_VALUE)); + } + final int resize = (int) newSize; + final int size = size(); + final byte[] newBuf = new byte[resize]; + System.arraycopy(content, 0, newBuf, 0, Math.min(resize, size)); + content = newBuf; + updateLastModified(); + } + + /** + * @param content The buffer. + */ + void setContent(final byte[] content) { + updateLastModified(); + this.content = content; + } + + /** + * @param lastModifiedMillis The lastModified to set. + */ + void setLastModified(final long lastModifiedMillis) { + this.lastModifiedMillis = lastModifiedMillis; + } + + /** + * @param type The type to set. + */ + void setType(final FileType type) { + this.type = type; + } + + /** + * @return Returns the size of the buffer + */ + int size() { + return content.length; + } + + /* + * (non-Javadoc) + * + * @see Object#toString() + */ + @Override + public String toString() { + return name.toString(); + } + + void updateLastModified() { + lastModifiedMillis = System.currentTimeMillis(); + } + +} diff --git a/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/ram/RamFileSystem.java b/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/ram/RamFileSystem.java index f4aff413a7..3f5498a617 100644 --- a/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/ram/RamFileSystem.java +++ b/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/ram/RamFileSystem.java @@ -1,248 +1,248 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.vfs2.provider.ram; - -import java.io.File; -import java.io.IOException; -import java.io.Serializable; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; - -import org.apache.commons.vfs2.Capability; -import org.apache.commons.vfs2.FileContent; -import org.apache.commons.vfs2.FileName; -import org.apache.commons.vfs2.FileObject; -import org.apache.commons.vfs2.FileSystemException; -import org.apache.commons.vfs2.FileSystemOptions; -import org.apache.commons.vfs2.FileType; -import org.apache.commons.vfs2.provider.AbstractFileName; -import org.apache.commons.vfs2.provider.AbstractFileSystem; - -/** - * A RAM File System. - */ -public class RamFileSystem extends AbstractFileSystem implements Serializable { - - /** - * serialVersionUID format is YYYYMMDD for the date of the last binary change. - */ - private static final long serialVersionUID = 20101208L; - - /** - * Cache of RAM File Data - */ - private final Map cache; - - /** - * Constructs a new instance. - * - * @param rootName The root file name of this file system. - * @param fileSystemOptions Options to build this file system. - */ - protected RamFileSystem(final FileName rootName, final FileSystemOptions fileSystemOptions) { - super(rootName, null, fileSystemOptions); - cache = Collections.synchronizedMap(new HashMap<>()); - // create root - final RamFileData rootData = new RamFileData(rootName); - rootData.setType(FileType.FOLDER); - rootData.setLastModified(System.currentTimeMillis()); - cache.put(rootName, rootData); - } - - /* - * (non-Javadoc) - * - * @see org.apache.commons.vfs2.provider.AbstractFileSystem#addCapabilities(java.util.Collection) - */ - @Override - protected void addCapabilities(final Collection caps) { - caps.addAll(RamFileProvider.capabilities); - } - - /** - * Attaches this instance to the given RamFileObject. - * - * @param ramFileObject A RAM file object. - */ - public void attach(final RamFileObject ramFileObject) { - if (ramFileObject.getName() == null) { - throw new IllegalArgumentException("Null argument"); - } - RamFileData data = cache.get(ramFileObject.getName()); - if (data == null) { - data = new RamFileData(ramFileObject.getName()); - } - ramFileObject.setData(data); - } - - /** - * Close the RAMFileSystem. - */ - @Override - public void close() { - cache.clear(); - super.close(); - } - - /* - * (non-Javadoc) - * - * @see org.apache.commons.vfs2.provider.AbstractFileSystem#createFile(org.apache.commons.vfs2.FileName) - */ - @Override - protected FileObject createFile(final AbstractFileName name) throws Exception { - return new RamFileObject(name, this); - } - - /** - * Delete a file - * - * @param file the {@link RamFileObject} file to delete. - * @throws FileSystemException Thrown for file system errors. - */ - void delete(final RamFileObject file) throws FileSystemException { - // root is read only check - FileSystemException.requireNonNull(file.getParent(), "unable to delete root"); - - // Remove reference from cache - cache.remove(file.getName()); - // Notify the parent - final RamFileObject parent = (RamFileObject) this.resolveFile(file.getParent().getName()); - parent.getData().removeChild(file.getData()); - parent.close(); - // Close the file - file.getData().clear(); - file.close(); - } - - /** - * Import a Tree. - * - * @param file The File - * @throws FileSystemException if an error occurs. - */ - public void importTree(final File file) throws FileSystemException { - final FileObject fileFo = getFileSystemManager().toFileObject(file); - toRamFileObject(fileFo, fileFo); - } - - /** - * @param name The name of the file. - * @return children The names of the children. - */ - String[] listChildren(final FileName name) { - final RamFileData data = cache.get(name); - if (data == null || !data.getType().hasChildren()) { - return null; - } - final Collection children = data.getChildren(); - - synchronized (children) { - return children.stream().filter(Objects::nonNull).map(childData -> childData.getName().getBaseName()).toArray(String[]::new); - } - } - - /** - * @param from The original file. - * @param to The new file. - * @throws FileSystemException if an error occurs. - */ - void rename(final RamFileObject from, final RamFileObject to) throws FileSystemException { - if (!cache.containsKey(from.getName())) { - throw new FileSystemException("File does not exist: " + from.getName()); - } - // Copy data - - to.getData().setContent(from.getData().getContent()); - to.getData().setLastModified(from.getData().getLastModified()); - to.getData().setType(from.getData().getType()); - - save(to); - delete(from); - } - - /** - * Saves a file - * - * @param file the {@link RamFileObject} file to save. - * @throws FileSystemException Thrown for file system errors. - */ - void save(final RamFileObject file) throws FileSystemException { - - // Validate name - if (file.getData().getName() == null) { - throw new FileSystemException(new IllegalStateException("The data has no name. " + file)); - } - - // Add to the parent - if (file.getName().getDepth() > 0) { - final RamFileData parentData = cache.get(file.getParent().getName()); - // Only if not already added - if (!parentData.hasChildren(file.getData())) { - final RamFileObject parent = (RamFileObject) file.getParent(); - parent.getData().addChild(file.getData()); - parent.close(); - } - } - // Store in cache - cache.put(file.getName(), file.getData()); - file.getData().updateLastModified(); - file.close(); - } - - /** - * @return Returns the size of the FileSystem - */ - long size() { - synchronized (cache) { - return cache.values().stream().mapToLong(RamFileData::size).sum(); - } - } - - /** - * Import the given file with the name relative to the given root - * - * @param fo the source {@link FileObject} file to import. - * @param root the {@link FileObject} root. - * @throws FileSystemException Thrown for file system errors. - */ - private void toRamFileObject(final FileObject fo, final FileObject root) throws FileSystemException { - final RamFileObject memFo = (RamFileObject) this - .resolveFile(fo.getName().getPath().substring(root.getName().getPath().length())); - if (fo.getType().hasChildren()) { - // Create Folder - memFo.createFolder(); - // Import recursively - final FileObject[] fos = fo.getChildren(); - for (final FileObject child : fos) { - toRamFileObject(child, root); - } - } else if (fo.isFile()) { - // Copy bytes - try (FileContent content = fo.getContent()) { - content.write(memFo); - } catch (final IOException e) { - throw new FileSystemException(e.getClass().getName() + " " + e.getMessage()); - } - } else { - throw new FileSystemException("File is not a folder nor a file " + memFo); - } - } -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.vfs2.provider.ram; + +import java.io.File; +import java.io.IOException; +import java.io.Serializable; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +import org.apache.commons.vfs2.Capability; +import org.apache.commons.vfs2.FileContent; +import org.apache.commons.vfs2.FileName; +import org.apache.commons.vfs2.FileObject; +import org.apache.commons.vfs2.FileSystemException; +import org.apache.commons.vfs2.FileSystemOptions; +import org.apache.commons.vfs2.FileType; +import org.apache.commons.vfs2.provider.AbstractFileName; +import org.apache.commons.vfs2.provider.AbstractFileSystem; + +/** + * A RAM File System. + */ +public class RamFileSystem extends AbstractFileSystem implements Serializable { + + /** + * serialVersionUID format is YYYYMMDD for the date of the last binary change. + */ + private static final long serialVersionUID = 20101208L; + + /** + * Cache of RAM File Data + */ + private final Map cache; + + /** + * Constructs a new instance. + * + * @param rootName The root file name of this file system. + * @param fileSystemOptions Options to build this file system. + */ + protected RamFileSystem(final FileName rootName, final FileSystemOptions fileSystemOptions) { + super(rootName, null, fileSystemOptions); + cache = Collections.synchronizedMap(new HashMap<>()); + // create root + final RamFileData rootData = new RamFileData(rootName); + rootData.setType(FileType.FOLDER); + rootData.setLastModified(System.currentTimeMillis()); + cache.put(rootName, rootData); + } + + /* + * (non-Javadoc) + * + * @see org.apache.commons.vfs2.provider.AbstractFileSystem#addCapabilities(java.util.Collection) + */ + @Override + protected void addCapabilities(final Collection caps) { + caps.addAll(RamFileProvider.capabilities); + } + + /** + * Attaches this instance to the given RamFileObject. + * + * @param ramFileObject A RAM file object. + */ + public void attach(final RamFileObject ramFileObject) { + if (ramFileObject.getName() == null) { + throw new IllegalArgumentException("Null argument"); + } + RamFileData data = cache.get(ramFileObject.getName()); + if (data == null) { + data = new RamFileData(ramFileObject.getName()); + } + ramFileObject.setData(data); + } + + /** + * Close the RAMFileSystem. + */ + @Override + public void close() { + cache.clear(); + super.close(); + } + + /* + * (non-Javadoc) + * + * @see org.apache.commons.vfs2.provider.AbstractFileSystem#createFile(org.apache.commons.vfs2.FileName) + */ + @Override + protected FileObject createFile(final AbstractFileName name) throws Exception { + return new RamFileObject(name, this); + } + + /** + * Delete a file + * + * @param file the {@link RamFileObject} file to delete. + * @throws FileSystemException Thrown for file system errors. + */ + void delete(final RamFileObject file) throws FileSystemException { + // root is read only check + FileSystemException.requireNonNull(file.getParent(), "unable to delete root"); + + // Remove reference from cache + cache.remove(file.getName()); + // Notify the parent + final RamFileObject parent = (RamFileObject) this.resolveFile(file.getParent().getName()); + parent.getData().removeChild(file.getData()); + parent.close(); + // Close the file + file.getData().clear(); + file.close(); + } + + /** + * Import a Tree. + * + * @param file The File + * @throws FileSystemException if an error occurs. + */ + public void importTree(final File file) throws FileSystemException { + final FileObject fileFo = getFileSystemManager().toFileObject(file); + toRamFileObject(fileFo, fileFo); + } + + /** + * @param name The name of the file. + * @return children The names of the children. + */ + String[] listChildren(final FileName name) { + final RamFileData data = cache.get(name); + if (data == null || !data.getType().hasChildren()) { + return null; + } + final Collection children = data.getChildren(); + + synchronized (children) { + return children.stream().filter(Objects::nonNull).map(childData -> childData.getName().getBaseName()).toArray(String[]::new); + } + } + + /** + * @param from The original file. + * @param to The new file. + * @throws FileSystemException if an error occurs. + */ + void rename(final RamFileObject from, final RamFileObject to) throws FileSystemException { + if (!cache.containsKey(from.getName())) { + throw new FileSystemException("File does not exist: " + from.getName()); + } + // Copy data + + to.getData().setContent(from.getData().getContent()); + to.getData().setLastModified(from.getData().getLastModified()); + to.getData().setType(from.getData().getType()); + + save(to); + delete(from); + } + + /** + * Saves a file + * + * @param file the {@link RamFileObject} file to save. + * @throws FileSystemException Thrown for file system errors. + */ + void save(final RamFileObject file) throws FileSystemException { + + // Validate name + if (file.getData().getName() == null) { + throw new FileSystemException(new IllegalStateException("The data has no name. " + file)); + } + + // Add to the parent + if (file.getName().getDepth() > 0) { + final RamFileData parentData = cache.get(file.getParent().getName()); + // Only if not already added + if (!parentData.hasChildren(file.getData())) { + final RamFileObject parent = (RamFileObject) file.getParent(); + parent.getData().addChild(file.getData()); + parent.close(); + } + } + // Store in cache + cache.put(file.getName(), file.getData()); + file.getData().updateLastModified(); + file.close(); + } + + /** + * @return Returns the size of the FileSystem + */ + long size() { + synchronized (cache) { + return cache.values().stream().mapToLong(RamFileData::size).sum(); + } + } + + /** + * Import the given file with the name relative to the given root + * + * @param fo the source {@link FileObject} file to import. + * @param root the {@link FileObject} root. + * @throws FileSystemException Thrown for file system errors. + */ + private void toRamFileObject(final FileObject fo, final FileObject root) throws FileSystemException { + final RamFileObject memFo = (RamFileObject) this + .resolveFile(fo.getName().getPath().substring(root.getName().getPath().length())); + if (fo.getType().hasChildren()) { + // Create Folder + memFo.createFolder(); + // Import recursively + final FileObject[] fos = fo.getChildren(); + for (final FileObject child : fos) { + toRamFileObject(child, root); + } + } else if (fo.isFile()) { + // Copy bytes + try (FileContent content = fo.getContent()) { + content.write(memFo); + } catch (final IOException e) { + throw new FileSystemException(e.getClass().getName() + " " + e.getMessage()); + } + } else { + throw new FileSystemException("File is not a folder nor a file " + memFo); + } + } +} diff --git a/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/sftp/BytesIdentityInfo.java b/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/sftp/BytesIdentityInfo.java index d74ff65af8..c444d860ed 100644 --- a/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/sftp/BytesIdentityInfo.java +++ b/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/sftp/BytesIdentityInfo.java @@ -1,122 +1,122 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.vfs2.provider.sftp; - -import java.util.Arrays; -import java.util.Objects; - -import com.jcraft.jsch.JSch; -import com.jcraft.jsch.JSchException; - -/** - * Structure for an identity based on byte arrays. - * - * @since 2.4 - */ -public class BytesIdentityInfo implements IdentityProvider { - - private final byte[] passphrase; - - private final byte[] privateKey; - - private final byte[] publicKey; - - /** - * Constructs an identity info with private and passphrase for the private key. - * - * @param privateKey Private key bytes - * @param passphrase The passphrase to decrypt the private key (can be {@code null} if no passphrase is used) - */ - public BytesIdentityInfo(final byte[] privateKey, final byte[] passphrase) { - this(privateKey, null, passphrase); - } - - /** - * Constructs an identity info with private and public key and passphrase for the private key. - * - * @param privateKey Private key bytes - * @param publicKey The public key part used for connections with exchange of certificates (can be {@code null}) - * @param passphrase The passphrase to decrypt the private key (can be {@code null} if no passphrase is used) - */ - public BytesIdentityInfo(final byte[] privateKey, final byte[] publicKey, final byte[] passphrase) { - this.privateKey = Utils.clone(privateKey); - this.publicKey = Utils.clone(publicKey); - this.passphrase = Utils.clone(passphrase); - } - - @Override - public void addIdentity(final JSch jsch) throws JSchException { - jsch.addIdentity("PrivateKey", privateKey, publicKey, passphrase); - } - - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (!(obj instanceof BytesIdentityInfo)) { - return false; - } - final BytesIdentityInfo other = (BytesIdentityInfo) obj; - return Arrays.equals(passphrase, other.passphrase) && Arrays.equals(privateKey, other.privateKey) && Arrays.equals(publicKey, other.publicKey); - } - - /** - * Gets the passphrase. - * - * @return the passphrase. - * @since 2.10.0 - */ - public byte[] getPassphrase() { - return Utils.clone(passphrase); - } - - /** - * Gets the passphrase. - * - * @return the passphrase. - * @deprecated Use {@link #getPassphrase()}. - */ - @Deprecated - public byte[] getPassPhrase() { - return Utils.clone(passphrase); - } - - /** - * Gets the private key. - * - * @return the private key. - */ - public byte[] getPrivateKeyBytes() { - return Utils.clone(privateKey); - } - - /** - * Gets the public key. - * - * @return the public key. - */ - public byte[] getPublicKeyBytes() { - return Utils.clone(publicKey); - } - - @Override - public int hashCode() { - return Objects.hash(Arrays.hashCode(passphrase), Arrays.hashCode(privateKey), Arrays.hashCode(publicKey)); - } -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.vfs2.provider.sftp; + +import java.util.Arrays; +import java.util.Objects; + +import com.jcraft.jsch.JSch; +import com.jcraft.jsch.JSchException; + +/** + * Structure for an identity based on byte arrays. + * + * @since 2.4 + */ +public class BytesIdentityInfo implements IdentityProvider { + + private final byte[] passphrase; + + private final byte[] privateKey; + + private final byte[] publicKey; + + /** + * Constructs an identity info with private and passphrase for the private key. + * + * @param privateKey Private key bytes + * @param passphrase The passphrase to decrypt the private key (can be {@code null} if no passphrase is used) + */ + public BytesIdentityInfo(final byte[] privateKey, final byte[] passphrase) { + this(privateKey, null, passphrase); + } + + /** + * Constructs an identity info with private and public key and passphrase for the private key. + * + * @param privateKey Private key bytes + * @param publicKey The public key part used for connections with exchange of certificates (can be {@code null}) + * @param passphrase The passphrase to decrypt the private key (can be {@code null} if no passphrase is used) + */ + public BytesIdentityInfo(final byte[] privateKey, final byte[] publicKey, final byte[] passphrase) { + this.privateKey = Utils.clone(privateKey); + this.publicKey = Utils.clone(publicKey); + this.passphrase = Utils.clone(passphrase); + } + + @Override + public void addIdentity(final JSch jsch) throws JSchException { + jsch.addIdentity("PrivateKey", privateKey, publicKey, passphrase); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof BytesIdentityInfo)) { + return false; + } + final BytesIdentityInfo other = (BytesIdentityInfo) obj; + return Arrays.equals(passphrase, other.passphrase) && Arrays.equals(privateKey, other.privateKey) && Arrays.equals(publicKey, other.publicKey); + } + + /** + * Gets the passphrase. + * + * @return the passphrase. + * @since 2.10.0 + */ + public byte[] getPassphrase() { + return Utils.clone(passphrase); + } + + /** + * Gets the passphrase. + * + * @return the passphrase. + * @deprecated Use {@link #getPassphrase()}. + */ + @Deprecated + public byte[] getPassPhrase() { + return Utils.clone(passphrase); + } + + /** + * Gets the private key. + * + * @return the private key. + */ + public byte[] getPrivateKeyBytes() { + return Utils.clone(privateKey); + } + + /** + * Gets the public key. + * + * @return the public key. + */ + public byte[] getPublicKeyBytes() { + return Utils.clone(publicKey); + } + + @Override + public int hashCode() { + return Objects.hash(Arrays.hashCode(passphrase), Arrays.hashCode(privateKey), Arrays.hashCode(publicKey)); + } +} diff --git a/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/sftp/IdentityInfo.java b/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/sftp/IdentityInfo.java index 1c2c12d8bd..fc4a2782f3 100644 --- a/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/sftp/IdentityInfo.java +++ b/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/sftp/IdentityInfo.java @@ -1,161 +1,161 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.vfs2.provider.sftp; - -import java.io.File; -import java.util.Arrays; -import java.util.Objects; - -import com.jcraft.jsch.JSch; -import com.jcraft.jsch.JSchException; - -/** - * Structure for an identity based on Files. - * - * @since 2.1 - */ -public class IdentityInfo implements IdentityProvider { - - private final byte[] passphrase; - private final File privateKey; - private final File publicKey; - - /** - * Constructs an identity info with private key. - *

- * The key is not passphrase protected. - *

- *

- * We use java.io.File because JSch cannot deal with VFS FileObjects. - *

- * - * @param privateKey The file with the private key - * @since 2.1 - */ - public IdentityInfo(final File privateKey) { - this(privateKey, null, null); - } - - /** - * Constructs an identity info with private key and its passphrase. - *

- * We use java.io.File because JSch cannot deal with VFS FileObjects. - *

- * - * @param privateKey The file with the private key - * @param passphrase The passphrase to decrypt the private key (can be {@code null} if no passphrase is used) - * @since 2.1 - */ - public IdentityInfo(final File privateKey, final byte[] passphrase) { - this(privateKey, null, passphrase); - } - - /** - * Constructs an identity info with private and public key and passphrase for the private key. - *

- * We use java.io.File because JSch cannot deal with VFS FileObjects. - *

- * - * @param privateKey The file with the private key - * @param publicKey The public key part used for connections with exchange of certificates (can be {@code null}) - * @param passphrase The passphrase to decrypt the private key (can be {@code null} if no passphrase is used) - * @since 2.1 - */ - public IdentityInfo(final File privateKey, final File publicKey, final byte[] passphrase) { - this.privateKey = getAbsoluteFile(privateKey); - this.publicKey = getAbsoluteFile(publicKey); - this.passphrase = Utils.clone(passphrase); - } - - /** - * @since 2.4 - */ - @Override - public void addIdentity(final JSch jsch) throws JSchException { - jsch.addIdentity(getAbsolutePath(privateKey), getAbsolutePath(publicKey), passphrase); - } - - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (!(obj instanceof IdentityInfo)) { - return false; - } - final IdentityInfo other = (IdentityInfo) obj; - return Arrays.equals(passphrase, other.passphrase) && Objects.equals(privateKey, other.privateKey) && Objects.equals(publicKey, other.publicKey); - } - - private File getAbsoluteFile(final File privateKey) { - return privateKey != null ? privateKey.getAbsoluteFile() : null; - } - - private String getAbsolutePath(final File file) { - return file != null ? file.getAbsolutePath() : null; - } - - /** - * Gets the passphrase of the private key. - * - * @return the passphrase - * @since 2.10.0 - */ - public byte[] getPassphrase() { - return Utils.clone(passphrase); - } - - /** - * Gets the passphrase of the private key. - * - * @return the passphrase - * @since 2.1 - * @deprecated Use {@link #getPassphrase()}. - */ - @Deprecated - public byte[] getPassPhrase() { - return Utils.clone(passphrase); - } - - /** - * Gets the file with the private key. - * - * @return the file - * @since 2.1 - */ - public File getPrivateKey() { - return privateKey; - } - - /** - * Gets the file with the public key. - * - * @return the file - * @since 2.1 - */ - public File getPublicKey() { - return publicKey; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + Arrays.hashCode(passphrase); - return prime * result + Objects.hash(privateKey, publicKey); - } -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.vfs2.provider.sftp; + +import java.io.File; +import java.util.Arrays; +import java.util.Objects; + +import com.jcraft.jsch.JSch; +import com.jcraft.jsch.JSchException; + +/** + * Structure for an identity based on Files. + * + * @since 2.1 + */ +public class IdentityInfo implements IdentityProvider { + + private final byte[] passphrase; + private final File privateKey; + private final File publicKey; + + /** + * Constructs an identity info with private key. + *

+ * The key is not passphrase protected. + *

+ *

+ * We use java.io.File because JSch cannot deal with VFS FileObjects. + *

+ * + * @param privateKey The file with the private key + * @since 2.1 + */ + public IdentityInfo(final File privateKey) { + this(privateKey, null, null); + } + + /** + * Constructs an identity info with private key and its passphrase. + *

+ * We use java.io.File because JSch cannot deal with VFS FileObjects. + *

+ * + * @param privateKey The file with the private key + * @param passphrase The passphrase to decrypt the private key (can be {@code null} if no passphrase is used) + * @since 2.1 + */ + public IdentityInfo(final File privateKey, final byte[] passphrase) { + this(privateKey, null, passphrase); + } + + /** + * Constructs an identity info with private and public key and passphrase for the private key. + *

+ * We use java.io.File because JSch cannot deal with VFS FileObjects. + *

+ * + * @param privateKey The file with the private key + * @param publicKey The public key part used for connections with exchange of certificates (can be {@code null}) + * @param passphrase The passphrase to decrypt the private key (can be {@code null} if no passphrase is used) + * @since 2.1 + */ + public IdentityInfo(final File privateKey, final File publicKey, final byte[] passphrase) { + this.privateKey = getAbsoluteFile(privateKey); + this.publicKey = getAbsoluteFile(publicKey); + this.passphrase = Utils.clone(passphrase); + } + + /** + * @since 2.4 + */ + @Override + public void addIdentity(final JSch jsch) throws JSchException { + jsch.addIdentity(getAbsolutePath(privateKey), getAbsolutePath(publicKey), passphrase); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof IdentityInfo)) { + return false; + } + final IdentityInfo other = (IdentityInfo) obj; + return Arrays.equals(passphrase, other.passphrase) && Objects.equals(privateKey, other.privateKey) && Objects.equals(publicKey, other.publicKey); + } + + private File getAbsoluteFile(final File privateKey) { + return privateKey != null ? privateKey.getAbsoluteFile() : null; + } + + private String getAbsolutePath(final File file) { + return file != null ? file.getAbsolutePath() : null; + } + + /** + * Gets the passphrase of the private key. + * + * @return the passphrase + * @since 2.10.0 + */ + public byte[] getPassphrase() { + return Utils.clone(passphrase); + } + + /** + * Gets the passphrase of the private key. + * + * @return the passphrase + * @since 2.1 + * @deprecated Use {@link #getPassphrase()}. + */ + @Deprecated + public byte[] getPassPhrase() { + return Utils.clone(passphrase); + } + + /** + * Gets the file with the private key. + * + * @return the file + * @since 2.1 + */ + public File getPrivateKey() { + return privateKey; + } + + /** + * Gets the file with the public key. + * + * @return the file + * @since 2.1 + */ + public File getPublicKey() { + return publicKey; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + Arrays.hashCode(passphrase); + return prime * result + Objects.hash(privateKey, publicKey); + } +} diff --git a/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/sftp/SftpFileSystemConfigBuilder.java b/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/sftp/SftpFileSystemConfigBuilder.java index f34d05b458..72f365be40 100644 --- a/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/sftp/SftpFileSystemConfigBuilder.java +++ b/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/sftp/SftpFileSystemConfigBuilder.java @@ -1,823 +1,823 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.vfs2.provider.sftp; - -import java.io.File; -import java.io.Serializable; -import java.time.Duration; -import java.util.Objects; -import java.util.stream.Stream; - -import org.apache.commons.vfs2.FileSystem; -import org.apache.commons.vfs2.FileSystemConfigBuilder; -import org.apache.commons.vfs2.FileSystemException; -import org.apache.commons.vfs2.FileSystemOptions; - -import com.jcraft.jsch.ConfigRepository; -import com.jcraft.jsch.UserInfo; - -/** - * The config builder for various SFTP configuration options. - */ -public final class SftpFileSystemConfigBuilder extends FileSystemConfigBuilder { - - /** - * Proxy type. - */ - public static final class ProxyType implements Serializable, Comparable { - - /** - * serialVersionUID format is YYYYMMDD for the date of the last binary change. - */ - private static final long serialVersionUID = 20101208L; - - /** - * The proxy type. - */ - private final String proxyType; - - private ProxyType(final String proxyType) { - this.proxyType = proxyType; - } - - @Override - public int compareTo(final ProxyType pType) { - return proxyType.compareTo(pType.proxyType); - } - - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (obj == null || this.getClass() != obj.getClass()) { - return false; - } - return Objects.equals(proxyType, ((ProxyType) obj).proxyType); - } - - /** - * @return a hash code value for this object. - * @since 2.0 - */ - @Override - public int hashCode() { - return proxyType.hashCode(); - } - } - - /** HTTP Proxy. */ - public static final ProxyType PROXY_HTTP = new ProxyType("http"); - - /** SOCKS Proxy. */ - public static final ProxyType PROXY_SOCKS5 = new ProxyType("socks"); - - /** - * Connects to the SFTP server through a remote host reached by SSH. - *

- * On this proxy host, a command (e.g. {@linkplain SftpStreamProxy#NETCAT_COMMAND} or - * {@linkplain SftpStreamProxy#NETCAT_COMMAND}) is run to forward input/output streams between the target host and - * the VFS host. - *

- *

- * When used, the proxy username ({@linkplain #setProxyUser}) and hostname ({@linkplain #setProxyHost}) must - * be set. Optionally, the command ({@linkplain #setProxyCommand}), password ({@linkplain #setProxyPassword}) and - * connection options ({@linkplain #setProxyOptions}) can be set. - *

- */ - public static final ProxyType PROXY_STREAM = new ProxyType("stream"); - - private static final Duration DEFAULT_CONNECT_TIMEOUT = Duration.ZERO; - - private static final Duration DEFAULT_SESSION_TIMEOUT = Duration.ZERO; - - private static final String PREFIX = SftpFileSystemConfigBuilder.class.getName(); - private static final SftpFileSystemConfigBuilder BUILDER = new SftpFileSystemConfigBuilder(); - private static final String COMPRESSION = PREFIX + "COMPRESSION"; - private static final String CONNECT_TIMEOUT = PREFIX + ".CONNECT_TIMEOUT"; - private static final String ENCODING = PREFIX + ".ENCODING"; - private static final String HOST_KEY_CHECK_ASK = "ask"; - private static final String HOST_KEY_CHECK_NO = "no"; - private static final String HOST_KEY_CHECK_YES = "yes"; - private static final String IDENTITIES = PREFIX + ".IDENTITIES"; - private static final String IDENTITY_REPOSITORY_FACTORY = PREFIX + "IDENTITY_REPOSITORY_FACTORY"; - private static final String CONFIG_REPOSITORY = PREFIX + "CONFIG_REPOSITORY"; - private static final String KEY_EXCHANGE_ALGORITHM = PREFIX + ".KEY_EXCHANGE_ALGORITHM"; - private static final String LOAD_OPENSSH_CONFIG = PREFIX + "LOAD_OPENSSH_CONFIG"; - private static final String KNOWN_HOSTS = PREFIX + ".KNOWN_HOSTS"; - private static final String PREFERRED_AUTHENTICATIONS = PREFIX + ".PREFERRED_AUTHENTICATIONS"; - private static final String PROXY_COMMAND = PREFIX + ".PROXY_COMMAND"; - private static final String PROXY_HOST = PREFIX + ".PROXY_HOST"; - private static final String PROXY_OPTIONS = PREFIX + ".PROXY_OPTIONS"; - private static final String PROXY_PASSWORD = PREFIX + ".PROXY_PASSWORD"; - private static final String PROXY_PORT = PREFIX + ".PROXY_PORT"; - private static final String DISABLE_DETECT_EXEC_CHANNEL = PREFIX + ".DISABLE_DETECT_EXEC_CHANNEL"; - - private static final String PROXY_TYPE = PREFIX + ".PROXY_TYPE"; - private static final String PROXY_USER = PREFIX + ".PROXY_USER"; - private static final String SESSION_TIMEOUT = PREFIX + ".TIMEOUT"; - private static final String STRICT_HOST_KEY_CHECKING = PREFIX + ".STRICT_HOST_KEY_CHECKING"; - private static final String USER_DIR_IS_ROOT = PREFIX + ".USER_DIR_IS_ROOT"; - - /** - * Gets the singleton builder. - * - * @return the singleton builder. - */ - public static SftpFileSystemConfigBuilder getInstance() { - return BUILDER; - } - - private SftpFileSystemConfigBuilder() { - super("sftp."); - } - - /** - * @param options The FileSystem options. - * @return The names of the compression algorithms, comma-separated. - * @see #setCompression - */ - public String getCompression(final FileSystemOptions options) { - return this.getString(options, COMPRESSION); - } - - @Override - protected Class getConfigClass() { - return SftpFileSystem.class; - } - - /** - * Gets the config repository. - * - * @param options The FileSystem options. - * @return the ConfigRepository - */ - public ConfigRepository getConfigRepository(final FileSystemOptions options) { - return getParam(options, CONFIG_REPOSITORY); - } - - /** - * Gets the connect timeout duration. - * - * @param options The FileSystem options. - * @return The connect timeout duration. - * @see #setConnectTimeoutMillis - * @since 2.8.0 - */ - public Duration getConnectTimeout(final FileSystemOptions options) { - return this.getDuration(options, CONNECT_TIMEOUT, DEFAULT_CONNECT_TIMEOUT); - } - - /** - * Gets the connect timeout duration. - * - * @param options The FileSystem options. - * @return The connect timeout value in milliseconds. - * @see #setConnectTimeoutMillis - * @since 2.3 - * @deprecated Use {@link #getConnectTimeout(FileSystemOptions)}. - */ - @Deprecated - public Integer getConnectTimeoutMillis(final FileSystemOptions options) { - return this.getDurationInteger(options, CONNECT_TIMEOUT, DEFAULT_CONNECT_TIMEOUT); - } - - /** - * Gets the file name encoding. - * - * @param options The FileSystem options. - * @return the file name encoding - */ - public String getFileNameEncoding(final FileSystemOptions options) { - return this.getString(options, ENCODING); - } - - /** - * Gets the identity files (your private key files). - *

- * We use java.io.File because JSch cannot deal with VFS FileObjects. - *

- * - * @param options The FileSystem options. - * @return the array of identity Files. - * @see #setIdentities - * @deprecated As of 2.1 use {@link #getIdentityInfo(FileSystemOptions)} - */ - @Deprecated - public File[] getIdentities(final FileSystemOptions options) { - final IdentityInfo[] info = getIdentityInfo(options); - if (info != null) { - return Stream.of(info).map(IdentityInfo::getPrivateKey).toArray(File[]::new); - } - return null; - } - - /** - * Gets the identity infos. - * - * @param options The FileSystem options. - * @return the array of identity info. - * @see #setIdentityInfo - */ - public IdentityInfo[] getIdentityInfo(final FileSystemOptions options) { - final IdentityProvider[] infos = getIdentityProvider(options); - if (infos != null) { - return Stream.of(infos).filter(IdentityInfo.class::isInstance).map(info -> (IdentityInfo) info).toArray(IdentityInfo[]::new); - } - return null; - } - - /** - * Gets the identity providers. - * - * @param options The FileSystem options. - * @return the array of identity providers. - * @see #setIdentityProvider - * @since 2.4 - */ - public IdentityProvider[] getIdentityProvider(final FileSystemOptions options) { - return getParam(options, IDENTITIES); - } - - /** - * Gets the identity repository factory. - * - * @param options The FileSystem options. - * @return the IdentityRepositoryFactory - */ - public IdentityRepositoryFactory getIdentityRepositoryFactory(final FileSystemOptions options) { - return getParam(options, IDENTITY_REPOSITORY_FACTORY); - } - - /** - * @param options The FileSystem options. - * @return the option value for specific key exchange algorithm - * @see #setKeyExchangeAlgorithm(FileSystemOptions, String) - * @since 2.4 - */ - public String getKeyExchangeAlgorithm(final FileSystemOptions options) { - return this.getString(options, KEY_EXCHANGE_ALGORITHM); - } - - /** - * @param options The FileSystem options. - * @return the known hosts File. - * @see #setKnownHosts - */ - public File getKnownHosts(final FileSystemOptions options) { - return getParam(options, KNOWN_HOSTS); - } - - /** - * Gets authentication order. - * - * @param options The FileSystem options. - * @return The authentication order. - * @since 2.0 - */ - public String getPreferredAuthentications(final FileSystemOptions options) { - return getString(options, PREFERRED_AUTHENTICATIONS); - } - - /** - * Gets the command that will be run on the proxy host when using a {@linkplain SftpStreamProxy}. The command - * defaults to {@linkplain SftpStreamProxy#NETCAT_COMMAND}. - * - * @param options The FileSystem options. - * @return proxyOptions - * @see SftpStreamProxy - * @see #setProxyOptions - * @since 2.1 - */ - public String getProxyCommand(final FileSystemOptions options) { - return this.getString(options, PROXY_COMMAND, SftpStreamProxy.NETCAT_COMMAND); - } - - /** - * Gets the proxy to use for the SFTP connection. - * - * @param options The FileSystem options. - * @return proxyHost - * @see #getProxyPort - * @see #setProxyHost - */ - public String getProxyHost(final FileSystemOptions options) { - return this.getString(options, PROXY_HOST); - } - - /** - * Gets the proxy options that are used to connect to the proxy host. - * - * @param options The FileSystem options. - * @return proxyOptions - * @see SftpStreamProxy - * @see #setProxyOptions - * @since 2.1 - */ - public FileSystemOptions getProxyOptions(final FileSystemOptions options) { - return getParam(options, PROXY_OPTIONS); - } - - /** - * Gets the proxy password that are used to connect to the proxy host. - * - * @param options The FileSystem options. - * @return proxyOptions - * @see SftpStreamProxy - * @see #setProxyPassword - * @since 2.1 - */ - public String getProxyPassword(final FileSystemOptions options) { - return this.getString(options, PROXY_PASSWORD); - } - - /** - * Gets the proxy-port to use for the SFTP the connection. - * - * @param options The FileSystem options. - * @return proxyPort: the port number or 0 if it is not set - * @see #setProxyPort - * @see #getProxyHost - */ - public int getProxyPort(final FileSystemOptions options) { - return this.getInteger(options, PROXY_PORT, 0); - } - - /** - * Gets the proxy type to use for the SFTP connection. - * - * @param options The FileSystem options. - * @return The ProxyType. - */ - public ProxyType getProxyType(final FileSystemOptions options) { - return getParam(options, PROXY_TYPE); - } - - /** - * Gets the user name for the proxy used for the SFTP connection. - * - * @param options The FileSystem options. - * @return proxyUser - * @see #setProxyUser - * @since 2.1 - */ - public String getProxyUser(final FileSystemOptions options) { - return this.getString(options, PROXY_USER); - } - - /** - * @param options The FileSystem options. - * @return The session timeout value in milliseconds. - * @see #setSessionTimeout - * @since 2.3 - */ - public Duration getSessionTimeout(final FileSystemOptions options) { - return this.getDuration(options, SESSION_TIMEOUT, DEFAULT_SESSION_TIMEOUT); - } - - /** - * @param options The FileSystem options. - * @return The session timeout value in milliseconds. - * @see #setSessionTimeoutMillis - * @since 2.3 - * @deprecated Use {@link #getSessionTimeout(FileSystemOptions)}. - */ - @Deprecated - public Integer getSessionTimeoutMillis(final FileSystemOptions options) { - return this.getDurationInteger(options, SESSION_TIMEOUT, DEFAULT_SESSION_TIMEOUT); - } - - /** - * @param options The FileSystem options. - * @return the option value The host key checking. - * @see #setStrictHostKeyChecking(FileSystemOptions, String) - */ - public String getStrictHostKeyChecking(final FileSystemOptions options) { - return this.getString(options, STRICT_HOST_KEY_CHECKING, HOST_KEY_CHECK_NO); - } - - /** - * @param options The FileSystem options. - * @return The timeout value in milliseconds. - * @see #setTimeout - * @deprecated Use {@link #getSessionTimeoutMillis(FileSystemOptions)} - */ - @Deprecated - public Integer getTimeout(final FileSystemOptions options) { - return this.getInteger(options, SESSION_TIMEOUT); - } - - /** - * Returns {@link Boolean#TRUE} if VFS should treat the user directory as the root directory. Defaults to - * {@code Boolean.TRUE} if the method {@link #setUserDirIsRoot(FileSystemOptions, boolean)} has not been - * invoked. - * - * @param options The FileSystemOptions. - * @return {@code Boolean.TRUE} if VFS treats the user directory as the root directory. - * @see #setUserDirIsRoot - */ - public Boolean getUserDirIsRoot(final FileSystemOptions options) { - return this.getBoolean(options, USER_DIR_IS_ROOT, Boolean.TRUE); - } - - /** - * @param options The FileSystem options. - * @return The UserInfo. - * @see #setUserInfo - */ - public UserInfo getUserInfo(final FileSystemOptions options) { - return getParam(options, UserInfo.class.getName()); - } - - /** - * Returns {@code true} if the detection of the exec channel should be disabled. - * Returns {@code false} if the detection of the exec channel should be enabled. - * Defaults to {@code false} if the method {@link #setDisableDetectExecChannel(FileSystemOptions, boolean)} has not been invoked. - * - * @param options The FileSystemOptions. - * @return {@code true} if detection of exec channel should be disabled. - * @see #setDisableDetectExecChannel(FileSystemOptions, boolean) - * @since 2.7.0 - */ - public boolean isDisableDetectExecChannel(final FileSystemOptions options) { - return this.getBoolean(options, DISABLE_DETECT_EXEC_CHANNEL, Boolean.FALSE); - } - - /** - * Returns {@link Boolean#TRUE} if VFS should load the OpenSSH config. Defaults to {@code Boolean.FALSE} if the - * method {@link #setLoadOpenSSHConfig(FileSystemOptions, boolean)} has not been invoked. - * - * @param options The FileSystemOptions. - * @return {@code Boolean.TRUE} if VFS should load the OpenSSH config. - * @see #setLoadOpenSSHConfig - */ - public boolean isLoadOpenSSHConfig(final FileSystemOptions options) { - return this.getBoolean(options, LOAD_OPENSSH_CONFIG, Boolean.FALSE); - } - - /** - * Configures the compression algorithms to use. - *

- * For example, use {@code "zlib,none"} to enable compression. - *

- *

- * See the Jsch documentation (in particular the README file) for details. - *

- * - * @param options The FileSystem options. - * @param compression The names of the compression algorithms, comma-separated. - */ - public void setCompression(final FileSystemOptions options, final String compression) { - this.setParam(options, COMPRESSION, compression); - } - - /** - * Sets the config repository. e.g. {@code /home/user/.ssh/config}. - *

- * This is useful when you want to use OpenSSHConfig. - *

- * - * @param options The FileSystem options. - * @param configRepository An config repository. - * @see OpenSSHConfig - */ - public void setConfigRepository(final FileSystemOptions options, final ConfigRepository configRepository) { - this.setParam(options, CONFIG_REPOSITORY, configRepository); - } - - /** - * Sets the timeout value to create a Jsch connection. - * - * @param options The FileSystem options. - * @param timeout The connect timeout in milliseconds. - * @since 2.8.0 - */ - public void setConnectTimeout(final FileSystemOptions options, final Duration timeout) { - this.setParam(options, CONNECT_TIMEOUT, timeout); - } - - /** - * Sets the timeout value to create a Jsch connection. - * - * @param options The FileSystem options. - * @param timeout The connect timeout in milliseconds. - * @since 2.3 - * @deprecated Use {@link #setConnectTimeout(FileSystemOptions, Duration)}. - */ - @Deprecated - public void setConnectTimeoutMillis(final FileSystemOptions options, final Integer timeout) { - setConnectTimeout(options, Duration.ofMillis(timeout)); - } - - /** - * Sets whether detection of exec channel is disabled. - * If this value is true the FileSystem will not test if the server allows to exec commands and disable the use of the exec channel. - * - * @param options The FileSystem options. - * @param disableDetectExecChannel true if the detection of exec channel should be disabled. - * @since 2.7.0 - */ - public void setDisableDetectExecChannel(final FileSystemOptions options, final boolean disableDetectExecChannel) { - this.setParam(options, DISABLE_DETECT_EXEC_CHANNEL, toBooleanObject(disableDetectExecChannel)); - } - - /** - * Sets the file name encoding. - * - * @param options The FileSystem options. - * @param fileNameEncoding The name of the encoding to use for file names. - */ - public void setFileNameEncoding(final FileSystemOptions options, final String fileNameEncoding) { - this.setParam(options, ENCODING, fileNameEncoding); - } - - /** - * Sets the identity files (your private key files). - *

- * We use {@link File} because JSch cannot deal with VFS FileObjects. - *

- * - * @param options The FileSystem options. - * @param identityFiles An array of identity Files. - * @deprecated As of 2.1 use {@link #setIdentityInfo(FileSystemOptions, IdentityInfo...)} - */ - @Deprecated - public void setIdentities(final FileSystemOptions options, final File... identityFiles) { - IdentityProvider[] info = null; - if (identityFiles != null) { - info = Stream.of(identityFiles).filter(Objects::nonNull).filter(Objects::nonNull).map(IdentityInfo::new).toArray(IdentityProvider[]::new); - } - this.setParam(options, IDENTITIES, info); - } - - /** - * Sets the identity info (your private key files). - * - * @param options The FileSystem options. - * @param identities An array of identity info. - * @since 2.1 - * @deprecated Use {@link #setIdentityProvider(FileSystemOptions,IdentityProvider...)} - */ - @Deprecated - public void setIdentityInfo(final FileSystemOptions options, final IdentityInfo... identities) { - this.setParam(options, IDENTITIES, identities); - } - - /** - * Sets the identity info (your private key files). - * - * @param options The FileSystem options. - * @param identities An array of identity info. - * @since 2.4 - */ - public void setIdentityProvider(final FileSystemOptions options, final IdentityProvider... identities) { - this.setParam(options, IDENTITIES, identities); - } - - /** - * Sets the identity repository. - *

- * This is useful when you want to use e.g. an SSH agent as provided. - *

- * - * @param options The FileSystem options. - * @param factory An identity repository. - * @see JSch agent proxy - */ - public void setIdentityRepositoryFactory(final FileSystemOptions options, final IdentityRepositoryFactory factory) { - this.setParam(options, IDENTITY_REPOSITORY_FACTORY, factory); - } - - /** - * Configures Key exchange algorithm explicitly e.g. diffie-hellman-group14-sha1, - * diffie-hellman-group-exchange-sha256, diffie-hellman-group-exchange-sha1, diffie-hellman-group1-sha1. - * - * @param options The FileSystem options. - * @param keyExchangeAlgorithm The key exchange algorithm picked. - * @since 2.4 - */ - public void setKeyExchangeAlgorithm(final FileSystemOptions options, final String keyExchangeAlgorithm) { - setParam(options, KEY_EXCHANGE_ALGORITHM, keyExchangeAlgorithm); - } - - /** - * Sets the known_hosts file. e.g. {@code /home/user/.ssh/known_hosts2}. - *

- * We use {@link File} because JSch cannot deal with VFS FileObjects. - *

- * - * @param options The FileSystem options. - * @param knownHosts The known hosts file. - */ - public void setKnownHosts(final FileSystemOptions options, final File knownHosts) { - this.setParam(options, KNOWN_HOSTS, knownHosts); - } - - /** - * Sets the whether to load OpenSSH config. - * - * @param options The FileSystem options. - * @param loadOpenSSHConfig true if the OpenSSH config should be loaded. - */ - public void setLoadOpenSSHConfig(final FileSystemOptions options, final boolean loadOpenSSHConfig) { - this.setParam(options, LOAD_OPENSSH_CONFIG, toBooleanObject(loadOpenSSHConfig)); - } - - /** - * Configures authentication order. - * - * @param options The FileSystem options. - * @param preferredAuthentications The authentication order. - * @since 2.0 - */ - public void setPreferredAuthentications(final FileSystemOptions options, final String preferredAuthentications) { - this.setParam(options, PREFERRED_AUTHENTICATIONS, preferredAuthentications); - } - - /** - * Sets the proxy username to use for the SFTP connection. - * - * @param options The FileSystem options. - * @param proxyCommand the port - * @see #getProxyOptions - * @since 2.1 - */ - public void setProxyCommand(final FileSystemOptions options, final String proxyCommand) { - this.setParam(options, PROXY_COMMAND, proxyCommand); - } - - /** - * Sets the proxy to use for the SFTP connection. - * - * You MUST also set the proxy port to use the proxy. - * - * @param options The FileSystem options. - * @param proxyHost the host - * @see #setProxyPort - */ - public void setProxyHost(final FileSystemOptions options, final String proxyHost) { - this.setParam(options, PROXY_HOST, proxyHost); - } - - /** - * Sets the proxy username to use for the SFTP connection. - * - * @param options The FileSystem options. - * @param proxyOptions the options - * @see #getProxyOptions - * @since 2.1 - */ - public void setProxyOptions(final FileSystemOptions options, final FileSystemOptions proxyOptions) { - this.setParam(options, PROXY_OPTIONS, proxyOptions); - } - - /** - * Sets the proxy password to use for the SFTP connection. - * - * @param options The FileSystem options. - * @param proxyPassword the username used to connect to the proxy - * @see #getProxyPassword - * @since 2.1 - */ - public void setProxyPassword(final FileSystemOptions options, final String proxyPassword) { - this.setParam(options, PROXY_PASSWORD, proxyPassword); - } - - /** - * Sets the proxy port to use for the SFTP connection. - *

- * You MUST also set the proxy host to use the proxy. - *

- * - * @param options The FileSystem options. - * @param proxyPort the port - * @see #setProxyHost - */ - public void setProxyPort(final FileSystemOptions options, final int proxyPort) { - this.setParam(options, PROXY_PORT, Integer.valueOf(proxyPort)); - } - - /** - * Sets the proxy type to use for the SFTP connection. - *

- * The possibles values are: - *

- *
    - *
  • {@linkplain #PROXY_HTTP} connects using an HTTP proxy
  • - *
  • {@linkplain #PROXY_SOCKS5} connects using an Socket5 proxy
  • - *
  • {@linkplain #PROXY_STREAM} connects through a remote host stream command
  • - *
- * - * @param options The FileSystem options. - * @param proxyType the type of the proxy to use. - */ - public void setProxyType(final FileSystemOptions options, final ProxyType proxyType) { - this.setParam(options, PROXY_TYPE, proxyType); - } - - /** - * Sets the proxy username to use for the SFTP connection. - * - * @param options The FileSystem options. - * @param proxyUser the username used to connect to the proxy - * @see #getProxyUser - * @since 2.1 - */ - public void setProxyUser(final FileSystemOptions options, final String proxyUser) { - this.setParam(options, PROXY_USER, proxyUser); - } - - /** - * Sets the timeout value on Jsch session. - * - * @param options The FileSystem options. - * @param timeout The session timeout in milliseconds. - * @since 2.8.0 - */ - public void setSessionTimeout(final FileSystemOptions options, final Duration timeout) { - this.setParam(options, SESSION_TIMEOUT, timeout); - } - - /** - * Sets the timeout value on Jsch session. - * - * @param options The FileSystem options. - * @param timeout The session timeout in milliseconds. - * @since 2.3 - * @deprecated Use {@link #setSessionTimeout(FileSystemOptions, Duration)}. - */ - @Deprecated - public void setSessionTimeoutMillis(final FileSystemOptions options, final Integer timeout) { - setSessionTimeout(options, Duration.ofMillis(timeout)); - } - - /** - * Configures the host key checking to use. - *

- * Valid arguments are: {@code "yes"}, {@code "no"} and {@code "ask"}. - *

- *

- * See the jsch documentation for details. - *

- * - * @param options The FileSystem options. - * @param hostKeyChecking The host key checking to use. - * @throws FileSystemException if an error occurs. - */ - public void setStrictHostKeyChecking(final FileSystemOptions options, final String hostKeyChecking) - throws FileSystemException { - if (hostKeyChecking == null || !hostKeyChecking.equals(HOST_KEY_CHECK_ASK) - && !hostKeyChecking.equals(HOST_KEY_CHECK_NO) && !hostKeyChecking.equals(HOST_KEY_CHECK_YES)) { - throw new FileSystemException("vfs.provider.sftp/StrictHostKeyChecking-arg.error", hostKeyChecking); - } - - this.setParam(options, STRICT_HOST_KEY_CHECKING, hostKeyChecking); - } - - /** - * Sets the timeout value on Jsch session. - * - * @param options The FileSystem options. - * @param timeout The timeout in milliseconds. - * @deprecated Use {@link #setSessionTimeout(FileSystemOptions, Duration)} - */ - @Deprecated - public void setTimeout(final FileSystemOptions options, final Integer timeout) { - this.setParam(options, SESSION_TIMEOUT, timeout); - } - - /** - * Sets the whether to use the user directory as root (do not change to file system root). - * - * @param options The FileSystem options. - * @param userDirIsRoot true if the user directory is the root directory. - */ - public void setUserDirIsRoot(final FileSystemOptions options, final boolean userDirIsRoot) { - this.setParam(options, USER_DIR_IS_ROOT, toBooleanObject(userDirIsRoot)); - } - - /** - * Sets the Jsch UserInfo class to use. - * - * @param options The FileSystem options. - * @param info User information. - */ - public void setUserInfo(final FileSystemOptions options, final UserInfo info) { - this.setParam(options, UserInfo.class.getName(), info); - } - -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.vfs2.provider.sftp; + +import java.io.File; +import java.io.Serializable; +import java.time.Duration; +import java.util.Objects; +import java.util.stream.Stream; + +import org.apache.commons.vfs2.FileSystem; +import org.apache.commons.vfs2.FileSystemConfigBuilder; +import org.apache.commons.vfs2.FileSystemException; +import org.apache.commons.vfs2.FileSystemOptions; + +import com.jcraft.jsch.ConfigRepository; +import com.jcraft.jsch.UserInfo; + +/** + * The config builder for various SFTP configuration options. + */ +public final class SftpFileSystemConfigBuilder extends FileSystemConfigBuilder { + + /** + * Proxy type. + */ + public static final class ProxyType implements Serializable, Comparable { + + /** + * serialVersionUID format is YYYYMMDD for the date of the last binary change. + */ + private static final long serialVersionUID = 20101208L; + + /** + * The proxy type. + */ + private final String proxyType; + + private ProxyType(final String proxyType) { + this.proxyType = proxyType; + } + + @Override + public int compareTo(final ProxyType pType) { + return proxyType.compareTo(pType.proxyType); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null || this.getClass() != obj.getClass()) { + return false; + } + return Objects.equals(proxyType, ((ProxyType) obj).proxyType); + } + + /** + * @return a hash code value for this object. + * @since 2.0 + */ + @Override + public int hashCode() { + return proxyType.hashCode(); + } + } + + /** HTTP Proxy. */ + public static final ProxyType PROXY_HTTP = new ProxyType("http"); + + /** SOCKS Proxy. */ + public static final ProxyType PROXY_SOCKS5 = new ProxyType("socks"); + + /** + * Connects to the SFTP server through a remote host reached by SSH. + *

+ * On this proxy host, a command (e.g. {@linkplain SftpStreamProxy#NETCAT_COMMAND} or + * {@linkplain SftpStreamProxy#NETCAT_COMMAND}) is run to forward input/output streams between the target host and + * the VFS host. + *

+ *

+ * When used, the proxy username ({@linkplain #setProxyUser}) and hostname ({@linkplain #setProxyHost}) must + * be set. Optionally, the command ({@linkplain #setProxyCommand}), password ({@linkplain #setProxyPassword}) and + * connection options ({@linkplain #setProxyOptions}) can be set. + *

+ */ + public static final ProxyType PROXY_STREAM = new ProxyType("stream"); + + private static final Duration DEFAULT_CONNECT_TIMEOUT = Duration.ZERO; + + private static final Duration DEFAULT_SESSION_TIMEOUT = Duration.ZERO; + + private static final String PREFIX = SftpFileSystemConfigBuilder.class.getName(); + private static final SftpFileSystemConfigBuilder BUILDER = new SftpFileSystemConfigBuilder(); + private static final String COMPRESSION = PREFIX + "COMPRESSION"; + private static final String CONNECT_TIMEOUT = PREFIX + ".CONNECT_TIMEOUT"; + private static final String ENCODING = PREFIX + ".ENCODING"; + private static final String HOST_KEY_CHECK_ASK = "ask"; + private static final String HOST_KEY_CHECK_NO = "no"; + private static final String HOST_KEY_CHECK_YES = "yes"; + private static final String IDENTITIES = PREFIX + ".IDENTITIES"; + private static final String IDENTITY_REPOSITORY_FACTORY = PREFIX + "IDENTITY_REPOSITORY_FACTORY"; + private static final String CONFIG_REPOSITORY = PREFIX + "CONFIG_REPOSITORY"; + private static final String KEY_EXCHANGE_ALGORITHM = PREFIX + ".KEY_EXCHANGE_ALGORITHM"; + private static final String LOAD_OPENSSH_CONFIG = PREFIX + "LOAD_OPENSSH_CONFIG"; + private static final String KNOWN_HOSTS = PREFIX + ".KNOWN_HOSTS"; + private static final String PREFERRED_AUTHENTICATIONS = PREFIX + ".PREFERRED_AUTHENTICATIONS"; + private static final String PROXY_COMMAND = PREFIX + ".PROXY_COMMAND"; + private static final String PROXY_HOST = PREFIX + ".PROXY_HOST"; + private static final String PROXY_OPTIONS = PREFIX + ".PROXY_OPTIONS"; + private static final String PROXY_PASSWORD = PREFIX + ".PROXY_PASSWORD"; + private static final String PROXY_PORT = PREFIX + ".PROXY_PORT"; + private static final String DISABLE_DETECT_EXEC_CHANNEL = PREFIX + ".DISABLE_DETECT_EXEC_CHANNEL"; + + private static final String PROXY_TYPE = PREFIX + ".PROXY_TYPE"; + private static final String PROXY_USER = PREFIX + ".PROXY_USER"; + private static final String SESSION_TIMEOUT = PREFIX + ".TIMEOUT"; + private static final String STRICT_HOST_KEY_CHECKING = PREFIX + ".STRICT_HOST_KEY_CHECKING"; + private static final String USER_DIR_IS_ROOT = PREFIX + ".USER_DIR_IS_ROOT"; + + /** + * Gets the singleton builder. + * + * @return the singleton builder. + */ + public static SftpFileSystemConfigBuilder getInstance() { + return BUILDER; + } + + private SftpFileSystemConfigBuilder() { + super("sftp."); + } + + /** + * @param options The FileSystem options. + * @return The names of the compression algorithms, comma-separated. + * @see #setCompression + */ + public String getCompression(final FileSystemOptions options) { + return this.getString(options, COMPRESSION); + } + + @Override + protected Class getConfigClass() { + return SftpFileSystem.class; + } + + /** + * Gets the config repository. + * + * @param options The FileSystem options. + * @return the ConfigRepository + */ + public ConfigRepository getConfigRepository(final FileSystemOptions options) { + return getParam(options, CONFIG_REPOSITORY); + } + + /** + * Gets the connect timeout duration. + * + * @param options The FileSystem options. + * @return The connect timeout duration. + * @see #setConnectTimeoutMillis + * @since 2.8.0 + */ + public Duration getConnectTimeout(final FileSystemOptions options) { + return this.getDuration(options, CONNECT_TIMEOUT, DEFAULT_CONNECT_TIMEOUT); + } + + /** + * Gets the connect timeout duration. + * + * @param options The FileSystem options. + * @return The connect timeout value in milliseconds. + * @see #setConnectTimeoutMillis + * @since 2.3 + * @deprecated Use {@link #getConnectTimeout(FileSystemOptions)}. + */ + @Deprecated + public Integer getConnectTimeoutMillis(final FileSystemOptions options) { + return this.getDurationInteger(options, CONNECT_TIMEOUT, DEFAULT_CONNECT_TIMEOUT); + } + + /** + * Gets the file name encoding. + * + * @param options The FileSystem options. + * @return the file name encoding + */ + public String getFileNameEncoding(final FileSystemOptions options) { + return this.getString(options, ENCODING); + } + + /** + * Gets the identity files (your private key files). + *

+ * We use java.io.File because JSch cannot deal with VFS FileObjects. + *

+ * + * @param options The FileSystem options. + * @return the array of identity Files. + * @see #setIdentities + * @deprecated As of 2.1 use {@link #getIdentityInfo(FileSystemOptions)} + */ + @Deprecated + public File[] getIdentities(final FileSystemOptions options) { + final IdentityInfo[] info = getIdentityInfo(options); + if (info != null) { + return Stream.of(info).map(IdentityInfo::getPrivateKey).toArray(File[]::new); + } + return null; + } + + /** + * Gets the identity infos. + * + * @param options The FileSystem options. + * @return the array of identity info. + * @see #setIdentityInfo + */ + public IdentityInfo[] getIdentityInfo(final FileSystemOptions options) { + final IdentityProvider[] infos = getIdentityProvider(options); + if (infos != null) { + return Stream.of(infos).filter(IdentityInfo.class::isInstance).map(info -> (IdentityInfo) info).toArray(IdentityInfo[]::new); + } + return null; + } + + /** + * Gets the identity providers. + * + * @param options The FileSystem options. + * @return the array of identity providers. + * @see #setIdentityProvider + * @since 2.4 + */ + public IdentityProvider[] getIdentityProvider(final FileSystemOptions options) { + return getParam(options, IDENTITIES); + } + + /** + * Gets the identity repository factory. + * + * @param options The FileSystem options. + * @return the IdentityRepositoryFactory + */ + public IdentityRepositoryFactory getIdentityRepositoryFactory(final FileSystemOptions options) { + return getParam(options, IDENTITY_REPOSITORY_FACTORY); + } + + /** + * @param options The FileSystem options. + * @return the option value for specific key exchange algorithm + * @see #setKeyExchangeAlgorithm(FileSystemOptions, String) + * @since 2.4 + */ + public String getKeyExchangeAlgorithm(final FileSystemOptions options) { + return this.getString(options, KEY_EXCHANGE_ALGORITHM); + } + + /** + * @param options The FileSystem options. + * @return the known hosts File. + * @see #setKnownHosts + */ + public File getKnownHosts(final FileSystemOptions options) { + return getParam(options, KNOWN_HOSTS); + } + + /** + * Gets authentication order. + * + * @param options The FileSystem options. + * @return The authentication order. + * @since 2.0 + */ + public String getPreferredAuthentications(final FileSystemOptions options) { + return getString(options, PREFERRED_AUTHENTICATIONS); + } + + /** + * Gets the command that will be run on the proxy host when using a {@linkplain SftpStreamProxy}. The command + * defaults to {@linkplain SftpStreamProxy#NETCAT_COMMAND}. + * + * @param options The FileSystem options. + * @return proxyOptions + * @see SftpStreamProxy + * @see #setProxyOptions + * @since 2.1 + */ + public String getProxyCommand(final FileSystemOptions options) { + return this.getString(options, PROXY_COMMAND, SftpStreamProxy.NETCAT_COMMAND); + } + + /** + * Gets the proxy to use for the SFTP connection. + * + * @param options The FileSystem options. + * @return proxyHost + * @see #getProxyPort + * @see #setProxyHost + */ + public String getProxyHost(final FileSystemOptions options) { + return this.getString(options, PROXY_HOST); + } + + /** + * Gets the proxy options that are used to connect to the proxy host. + * + * @param options The FileSystem options. + * @return proxyOptions + * @see SftpStreamProxy + * @see #setProxyOptions + * @since 2.1 + */ + public FileSystemOptions getProxyOptions(final FileSystemOptions options) { + return getParam(options, PROXY_OPTIONS); + } + + /** + * Gets the proxy password that are used to connect to the proxy host. + * + * @param options The FileSystem options. + * @return proxyOptions + * @see SftpStreamProxy + * @see #setProxyPassword + * @since 2.1 + */ + public String getProxyPassword(final FileSystemOptions options) { + return this.getString(options, PROXY_PASSWORD); + } + + /** + * Gets the proxy-port to use for the SFTP the connection. + * + * @param options The FileSystem options. + * @return proxyPort: the port number or 0 if it is not set + * @see #setProxyPort + * @see #getProxyHost + */ + public int getProxyPort(final FileSystemOptions options) { + return this.getInteger(options, PROXY_PORT, 0); + } + + /** + * Gets the proxy type to use for the SFTP connection. + * + * @param options The FileSystem options. + * @return The ProxyType. + */ + public ProxyType getProxyType(final FileSystemOptions options) { + return getParam(options, PROXY_TYPE); + } + + /** + * Gets the user name for the proxy used for the SFTP connection. + * + * @param options The FileSystem options. + * @return proxyUser + * @see #setProxyUser + * @since 2.1 + */ + public String getProxyUser(final FileSystemOptions options) { + return this.getString(options, PROXY_USER); + } + + /** + * @param options The FileSystem options. + * @return The session timeout value in milliseconds. + * @see #setSessionTimeout + * @since 2.3 + */ + public Duration getSessionTimeout(final FileSystemOptions options) { + return this.getDuration(options, SESSION_TIMEOUT, DEFAULT_SESSION_TIMEOUT); + } + + /** + * @param options The FileSystem options. + * @return The session timeout value in milliseconds. + * @see #setSessionTimeoutMillis + * @since 2.3 + * @deprecated Use {@link #getSessionTimeout(FileSystemOptions)}. + */ + @Deprecated + public Integer getSessionTimeoutMillis(final FileSystemOptions options) { + return this.getDurationInteger(options, SESSION_TIMEOUT, DEFAULT_SESSION_TIMEOUT); + } + + /** + * @param options The FileSystem options. + * @return the option value The host key checking. + * @see #setStrictHostKeyChecking(FileSystemOptions, String) + */ + public String getStrictHostKeyChecking(final FileSystemOptions options) { + return this.getString(options, STRICT_HOST_KEY_CHECKING, HOST_KEY_CHECK_NO); + } + + /** + * @param options The FileSystem options. + * @return The timeout value in milliseconds. + * @see #setTimeout + * @deprecated Use {@link #getSessionTimeoutMillis(FileSystemOptions)} + */ + @Deprecated + public Integer getTimeout(final FileSystemOptions options) { + return this.getInteger(options, SESSION_TIMEOUT); + } + + /** + * Returns {@link Boolean#TRUE} if VFS should treat the user directory as the root directory. Defaults to + * {@code Boolean.TRUE} if the method {@link #setUserDirIsRoot(FileSystemOptions, boolean)} has not been + * invoked. + * + * @param options The FileSystemOptions. + * @return {@code Boolean.TRUE} if VFS treats the user directory as the root directory. + * @see #setUserDirIsRoot + */ + public Boolean getUserDirIsRoot(final FileSystemOptions options) { + return this.getBoolean(options, USER_DIR_IS_ROOT, Boolean.TRUE); + } + + /** + * @param options The FileSystem options. + * @return The UserInfo. + * @see #setUserInfo + */ + public UserInfo getUserInfo(final FileSystemOptions options) { + return getParam(options, UserInfo.class.getName()); + } + + /** + * Returns {@code true} if the detection of the exec channel should be disabled. + * Returns {@code false} if the detection of the exec channel should be enabled. + * Defaults to {@code false} if the method {@link #setDisableDetectExecChannel(FileSystemOptions, boolean)} has not been invoked. + * + * @param options The FileSystemOptions. + * @return {@code true} if detection of exec channel should be disabled. + * @see #setDisableDetectExecChannel(FileSystemOptions, boolean) + * @since 2.7.0 + */ + public boolean isDisableDetectExecChannel(final FileSystemOptions options) { + return this.getBoolean(options, DISABLE_DETECT_EXEC_CHANNEL, Boolean.FALSE); + } + + /** + * Returns {@link Boolean#TRUE} if VFS should load the OpenSSH config. Defaults to {@code Boolean.FALSE} if the + * method {@link #setLoadOpenSSHConfig(FileSystemOptions, boolean)} has not been invoked. + * + * @param options The FileSystemOptions. + * @return {@code Boolean.TRUE} if VFS should load the OpenSSH config. + * @see #setLoadOpenSSHConfig + */ + public boolean isLoadOpenSSHConfig(final FileSystemOptions options) { + return this.getBoolean(options, LOAD_OPENSSH_CONFIG, Boolean.FALSE); + } + + /** + * Configures the compression algorithms to use. + *

+ * For example, use {@code "zlib,none"} to enable compression. + *

+ *

+ * See the Jsch documentation (in particular the README file) for details. + *

+ * + * @param options The FileSystem options. + * @param compression The names of the compression algorithms, comma-separated. + */ + public void setCompression(final FileSystemOptions options, final String compression) { + this.setParam(options, COMPRESSION, compression); + } + + /** + * Sets the config repository. e.g. {@code /home/user/.ssh/config}. + *

+ * This is useful when you want to use OpenSSHConfig. + *

+ * + * @param options The FileSystem options. + * @param configRepository An config repository. + * @see OpenSSHConfig + */ + public void setConfigRepository(final FileSystemOptions options, final ConfigRepository configRepository) { + this.setParam(options, CONFIG_REPOSITORY, configRepository); + } + + /** + * Sets the timeout value to create a Jsch connection. + * + * @param options The FileSystem options. + * @param timeout The connect timeout in milliseconds. + * @since 2.8.0 + */ + public void setConnectTimeout(final FileSystemOptions options, final Duration timeout) { + this.setParam(options, CONNECT_TIMEOUT, timeout); + } + + /** + * Sets the timeout value to create a Jsch connection. + * + * @param options The FileSystem options. + * @param timeout The connect timeout in milliseconds. + * @since 2.3 + * @deprecated Use {@link #setConnectTimeout(FileSystemOptions, Duration)}. + */ + @Deprecated + public void setConnectTimeoutMillis(final FileSystemOptions options, final Integer timeout) { + setConnectTimeout(options, Duration.ofMillis(timeout)); + } + + /** + * Sets whether detection of exec channel is disabled. + * If this value is true the FileSystem will not test if the server allows to exec commands and disable the use of the exec channel. + * + * @param options The FileSystem options. + * @param disableDetectExecChannel true if the detection of exec channel should be disabled. + * @since 2.7.0 + */ + public void setDisableDetectExecChannel(final FileSystemOptions options, final boolean disableDetectExecChannel) { + this.setParam(options, DISABLE_DETECT_EXEC_CHANNEL, toBooleanObject(disableDetectExecChannel)); + } + + /** + * Sets the file name encoding. + * + * @param options The FileSystem options. + * @param fileNameEncoding The name of the encoding to use for file names. + */ + public void setFileNameEncoding(final FileSystemOptions options, final String fileNameEncoding) { + this.setParam(options, ENCODING, fileNameEncoding); + } + + /** + * Sets the identity files (your private key files). + *

+ * We use {@link File} because JSch cannot deal with VFS FileObjects. + *

+ * + * @param options The FileSystem options. + * @param identityFiles An array of identity Files. + * @deprecated As of 2.1 use {@link #setIdentityInfo(FileSystemOptions, IdentityInfo...)} + */ + @Deprecated + public void setIdentities(final FileSystemOptions options, final File... identityFiles) { + IdentityProvider[] info = null; + if (identityFiles != null) { + info = Stream.of(identityFiles).filter(Objects::nonNull).filter(Objects::nonNull).map(IdentityInfo::new).toArray(IdentityProvider[]::new); + } + this.setParam(options, IDENTITIES, info); + } + + /** + * Sets the identity info (your private key files). + * + * @param options The FileSystem options. + * @param identities An array of identity info. + * @since 2.1 + * @deprecated Use {@link #setIdentityProvider(FileSystemOptions,IdentityProvider...)} + */ + @Deprecated + public void setIdentityInfo(final FileSystemOptions options, final IdentityInfo... identities) { + this.setParam(options, IDENTITIES, identities); + } + + /** + * Sets the identity info (your private key files). + * + * @param options The FileSystem options. + * @param identities An array of identity info. + * @since 2.4 + */ + public void setIdentityProvider(final FileSystemOptions options, final IdentityProvider... identities) { + this.setParam(options, IDENTITIES, identities); + } + + /** + * Sets the identity repository. + *

+ * This is useful when you want to use e.g. an SSH agent as provided. + *

+ * + * @param options The FileSystem options. + * @param factory An identity repository. + * @see JSch agent proxy + */ + public void setIdentityRepositoryFactory(final FileSystemOptions options, final IdentityRepositoryFactory factory) { + this.setParam(options, IDENTITY_REPOSITORY_FACTORY, factory); + } + + /** + * Configures Key exchange algorithm explicitly e.g. diffie-hellman-group14-sha1, + * diffie-hellman-group-exchange-sha256, diffie-hellman-group-exchange-sha1, diffie-hellman-group1-sha1. + * + * @param options The FileSystem options. + * @param keyExchangeAlgorithm The key exchange algorithm picked. + * @since 2.4 + */ + public void setKeyExchangeAlgorithm(final FileSystemOptions options, final String keyExchangeAlgorithm) { + setParam(options, KEY_EXCHANGE_ALGORITHM, keyExchangeAlgorithm); + } + + /** + * Sets the known_hosts file. e.g. {@code /home/user/.ssh/known_hosts2}. + *

+ * We use {@link File} because JSch cannot deal with VFS FileObjects. + *

+ * + * @param options The FileSystem options. + * @param knownHosts The known hosts file. + */ + public void setKnownHosts(final FileSystemOptions options, final File knownHosts) { + this.setParam(options, KNOWN_HOSTS, knownHosts); + } + + /** + * Sets the whether to load OpenSSH config. + * + * @param options The FileSystem options. + * @param loadOpenSSHConfig true if the OpenSSH config should be loaded. + */ + public void setLoadOpenSSHConfig(final FileSystemOptions options, final boolean loadOpenSSHConfig) { + this.setParam(options, LOAD_OPENSSH_CONFIG, toBooleanObject(loadOpenSSHConfig)); + } + + /** + * Configures authentication order. + * + * @param options The FileSystem options. + * @param preferredAuthentications The authentication order. + * @since 2.0 + */ + public void setPreferredAuthentications(final FileSystemOptions options, final String preferredAuthentications) { + this.setParam(options, PREFERRED_AUTHENTICATIONS, preferredAuthentications); + } + + /** + * Sets the proxy username to use for the SFTP connection. + * + * @param options The FileSystem options. + * @param proxyCommand the port + * @see #getProxyOptions + * @since 2.1 + */ + public void setProxyCommand(final FileSystemOptions options, final String proxyCommand) { + this.setParam(options, PROXY_COMMAND, proxyCommand); + } + + /** + * Sets the proxy to use for the SFTP connection. + * + * You MUST also set the proxy port to use the proxy. + * + * @param options The FileSystem options. + * @param proxyHost the host + * @see #setProxyPort + */ + public void setProxyHost(final FileSystemOptions options, final String proxyHost) { + this.setParam(options, PROXY_HOST, proxyHost); + } + + /** + * Sets the proxy username to use for the SFTP connection. + * + * @param options The FileSystem options. + * @param proxyOptions the options + * @see #getProxyOptions + * @since 2.1 + */ + public void setProxyOptions(final FileSystemOptions options, final FileSystemOptions proxyOptions) { + this.setParam(options, PROXY_OPTIONS, proxyOptions); + } + + /** + * Sets the proxy password to use for the SFTP connection. + * + * @param options The FileSystem options. + * @param proxyPassword the username used to connect to the proxy + * @see #getProxyPassword + * @since 2.1 + */ + public void setProxyPassword(final FileSystemOptions options, final String proxyPassword) { + this.setParam(options, PROXY_PASSWORD, proxyPassword); + } + + /** + * Sets the proxy port to use for the SFTP connection. + *

+ * You MUST also set the proxy host to use the proxy. + *

+ * + * @param options The FileSystem options. + * @param proxyPort the port + * @see #setProxyHost + */ + public void setProxyPort(final FileSystemOptions options, final int proxyPort) { + this.setParam(options, PROXY_PORT, Integer.valueOf(proxyPort)); + } + + /** + * Sets the proxy type to use for the SFTP connection. + *

+ * The possibles values are: + *

+ *
    + *
  • {@linkplain #PROXY_HTTP} connects using an HTTP proxy
  • + *
  • {@linkplain #PROXY_SOCKS5} connects using an Socket5 proxy
  • + *
  • {@linkplain #PROXY_STREAM} connects through a remote host stream command
  • + *
+ * + * @param options The FileSystem options. + * @param proxyType the type of the proxy to use. + */ + public void setProxyType(final FileSystemOptions options, final ProxyType proxyType) { + this.setParam(options, PROXY_TYPE, proxyType); + } + + /** + * Sets the proxy username to use for the SFTP connection. + * + * @param options The FileSystem options. + * @param proxyUser the username used to connect to the proxy + * @see #getProxyUser + * @since 2.1 + */ + public void setProxyUser(final FileSystemOptions options, final String proxyUser) { + this.setParam(options, PROXY_USER, proxyUser); + } + + /** + * Sets the timeout value on Jsch session. + * + * @param options The FileSystem options. + * @param timeout The session timeout in milliseconds. + * @since 2.8.0 + */ + public void setSessionTimeout(final FileSystemOptions options, final Duration timeout) { + this.setParam(options, SESSION_TIMEOUT, timeout); + } + + /** + * Sets the timeout value on Jsch session. + * + * @param options The FileSystem options. + * @param timeout The session timeout in milliseconds. + * @since 2.3 + * @deprecated Use {@link #setSessionTimeout(FileSystemOptions, Duration)}. + */ + @Deprecated + public void setSessionTimeoutMillis(final FileSystemOptions options, final Integer timeout) { + setSessionTimeout(options, Duration.ofMillis(timeout)); + } + + /** + * Configures the host key checking to use. + *

+ * Valid arguments are: {@code "yes"}, {@code "no"} and {@code "ask"}. + *

+ *

+ * See the jsch documentation for details. + *

+ * + * @param options The FileSystem options. + * @param hostKeyChecking The host key checking to use. + * @throws FileSystemException if an error occurs. + */ + public void setStrictHostKeyChecking(final FileSystemOptions options, final String hostKeyChecking) + throws FileSystemException { + if (hostKeyChecking == null || !hostKeyChecking.equals(HOST_KEY_CHECK_ASK) + && !hostKeyChecking.equals(HOST_KEY_CHECK_NO) && !hostKeyChecking.equals(HOST_KEY_CHECK_YES)) { + throw new FileSystemException("vfs.provider.sftp/StrictHostKeyChecking-arg.error", hostKeyChecking); + } + + this.setParam(options, STRICT_HOST_KEY_CHECKING, hostKeyChecking); + } + + /** + * Sets the timeout value on Jsch session. + * + * @param options The FileSystem options. + * @param timeout The timeout in milliseconds. + * @deprecated Use {@link #setSessionTimeout(FileSystemOptions, Duration)} + */ + @Deprecated + public void setTimeout(final FileSystemOptions options, final Integer timeout) { + this.setParam(options, SESSION_TIMEOUT, timeout); + } + + /** + * Sets the whether to use the user directory as root (do not change to file system root). + * + * @param options The FileSystem options. + * @param userDirIsRoot true if the user directory is the root directory. + */ + public void setUserDirIsRoot(final FileSystemOptions options, final boolean userDirIsRoot) { + this.setParam(options, USER_DIR_IS_ROOT, toBooleanObject(userDirIsRoot)); + } + + /** + * Sets the Jsch UserInfo class to use. + * + * @param options The FileSystem options. + * @param info User information. + */ + public void setUserInfo(final FileSystemOptions options, final UserInfo info) { + this.setParam(options, UserInfo.class.getName(), info); + } + +} diff --git a/commons-vfs2/src/site/xdoc/index.xml b/commons-vfs2/src/site/xdoc/index.xml index 775963b722..9a8b0153a3 100644 --- a/commons-vfs2/src/site/xdoc/index.xml +++ b/commons-vfs2/src/site/xdoc/index.xml @@ -1,39 +1,39 @@ - - - - - - Apache Commons VFS Core - Apache Commons Developers - - - - -
-

- This is the core module containing the Apache Commons VFS API, - implementation as well as various - file system providers. -

- The documentation on how to use the API can be found in the - parent module. -

-
- - -
+ + + + + + Apache Commons VFS Core + Apache Commons Developers + + + + +
+

+ This is the core module containing the Apache Commons VFS API, + implementation as well as various + file system providers. +

+ The documentation on how to use the API can be found in the + parent module. +

+
+ + +
diff --git a/commons-vfs2/src/test/java/org/apache/commons/vfs2/FileSystemOptionsTest.java b/commons-vfs2/src/test/java/org/apache/commons/vfs2/FileSystemOptionsTest.java index 1e59fe4595..e9b0bd6854 100644 --- a/commons-vfs2/src/test/java/org/apache/commons/vfs2/FileSystemOptionsTest.java +++ b/commons-vfs2/src/test/java/org/apache/commons/vfs2/FileSystemOptionsTest.java @@ -1,162 +1,162 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.vfs2; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotEquals; -import static org.junit.jupiter.api.Assertions.assertNull; - -import java.io.File; - -import org.apache.commons.vfs2.provider.sftp.IdentityInfo; -import org.apache.commons.vfs2.provider.sftp.SftpFileSystemConfigBuilder; -import org.junit.jupiter.api.Test; - -/** - * Check FileSystemOptions. - */ -public class FileSystemOptionsTest { - - public static class JUnitConfigBuilder extends FileSystemConfigBuilder { - private abstract static class JUnitFS implements FileSystem { - } - - private static final JUnitConfigBuilder BUILDER = new JUnitConfigBuilder(); - - public static JUnitConfigBuilder getInstance() { - return BUILDER; - } - - @Override - protected Class getConfigClass() { - return JUnitFS.class; - } - - public void setId(final FileSystemOptions opts, final String id) { - setParam(opts, "id", id); - } - - public void setNames(final FileSystemOptions opts, final String[] names) { - setParam(opts, "names", names); - } - } - - private static void assertSftpOptionsEquals(final File privKey, final File pubKey, final byte[] passphrase) { - final SftpFileSystemConfigBuilder builder = SftpFileSystemConfigBuilder.getInstance(); - - final FileSystemOptions expected = new FileSystemOptions(); - final IdentityInfo info1 = new IdentityInfo(privKey, pubKey, passphrase); - builder.setIdentityProvider(expected, info1); - - final FileSystemOptions actual = new FileSystemOptions(); - final IdentityInfo info2 = new IdentityInfo(privKey, pubKey, passphrase); - builder.setIdentityProvider(actual, info2); - - assertEquals(0, expected.compareTo(actual)); - assertEquals(expected.hashCode(), actual.hashCode()); - } - - private static void assertSftpOptionsNotEquals(final File privKey1, final File pubKey1, final byte[] passphrase1, - final File privKey2, final File pubKey2, final byte[] passphrase2) { - final SftpFileSystemConfigBuilder builder = SftpFileSystemConfigBuilder.getInstance(); - - final FileSystemOptions expected = new FileSystemOptions(); - final IdentityInfo info1 = new IdentityInfo(privKey1, pubKey1, passphrase1); - builder.setIdentityProvider(expected, info1); - - final FileSystemOptions actual = new FileSystemOptions(); - final IdentityInfo info2 = new IdentityInfo(privKey2, pubKey2, passphrase2); - builder.setIdentityProvider(actual, info2); - - assertNotEquals(0, expected.compareTo(actual)); - assertNotEquals(expected.hashCode(), actual.hashCode()); - } - - @Test - public void testClone() { - final FileSystemOptions fileSystemOptions = new FileSystemOptions(); - assertEquals(fileSystemOptions.getClass(), fileSystemOptions.clone().getClass()); - assertEquals(0, ((FileSystemOptions) fileSystemOptions.clone()).size()); - fileSystemOptions.setOption(FileSystem.class, "key1", "value1"); - assertEquals(1, ((FileSystemOptions) fileSystemOptions.clone()).size()); - final FileSystemOptions clone = (FileSystemOptions) fileSystemOptions.clone(); - assertEquals("value1", clone.getOption(FileSystem.class, "key1")); - fileSystemOptions.setOption(FileSystem.class, "key2", "value2"); - assertNull(clone.getOption(FileSystem.class, "key2")); - } - - @Test - public void testEqualsHashCodeAndCompareTo() { - final JUnitConfigBuilder builder = JUnitConfigBuilder.getInstance(); - final FileSystemOptions expected = new FileSystemOptions(); - builder.setId(expected, "Test"); - - final FileSystemOptions actual = new FileSystemOptions(); - builder.setId(actual, "Test"); - - assertEquals(expected, actual); - assertEquals(0, actual.compareTo(expected)); - assertEquals(expected.hashCode(), actual.hashCode()); - - builder.setNames(expected, new String[] {"A", "B", "C"}); - - assertNotEquals(expected, actual); - assertEquals(-1, actual.compareTo(expected)); - assertNotEquals(expected.hashCode(), actual.hashCode()); - - builder.setNames(actual, new String[] {"A", "B", "C"}); - - assertEquals(expected, actual); - assertEquals(0, actual.compareTo(expected)); - assertEquals(expected.hashCode(), actual.hashCode()); - } - - @Test - public void testEqualsHashCodeAndCompareToWithSftpIdentityProviderMatch() { - for (int mask = 0; mask < 8; mask++) { - assertSftpOptionsEquals( - (mask & 1) == 1 ? new File("/tmp/test.priv") : null, - (mask & 2) == 2 ? new File("/tmp/test.pub") : null, - (mask & 4) == 4 ? new byte[] {1, 2, 3} : null - ); - } - } - - @Test - public void testEqualsHashCodeAndCompareToWithSftpIdentityProviderMismatch() { - final String pubKey1 = "/tmp/test.pub"; - final String pubKey2 = "/tmp/test1.pub"; - - final String privKey1 = "/tmp/test.priv"; - final String privKey2 = "/tmp/test1.priv"; - - assertSftpOptionsNotEquals( - new File(privKey1), new File(pubKey1), new byte[] {1, 2, 3}, - new File(privKey2), new File(pubKey1), new byte[] {1, 2, 3} - ); - - assertSftpOptionsNotEquals( - new File(privKey1), new File(pubKey1), new byte[] {1, 2, 3}, - new File(privKey1), new File(pubKey2), new byte[] {1, 2, 3} - ); - - assertSftpOptionsNotEquals( - new File(privKey1), new File(pubKey1), new byte[] {1, 2, 3}, - new File(privKey1), new File(pubKey1), new byte[] {1, 2, 4} - ); - } -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.vfs2; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +import java.io.File; + +import org.apache.commons.vfs2.provider.sftp.IdentityInfo; +import org.apache.commons.vfs2.provider.sftp.SftpFileSystemConfigBuilder; +import org.junit.jupiter.api.Test; + +/** + * Check FileSystemOptions. + */ +public class FileSystemOptionsTest { + + public static class JUnitConfigBuilder extends FileSystemConfigBuilder { + private abstract static class JUnitFS implements FileSystem { + } + + private static final JUnitConfigBuilder BUILDER = new JUnitConfigBuilder(); + + public static JUnitConfigBuilder getInstance() { + return BUILDER; + } + + @Override + protected Class getConfigClass() { + return JUnitFS.class; + } + + public void setId(final FileSystemOptions opts, final String id) { + setParam(opts, "id", id); + } + + public void setNames(final FileSystemOptions opts, final String[] names) { + setParam(opts, "names", names); + } + } + + private static void assertSftpOptionsEquals(final File privKey, final File pubKey, final byte[] passphrase) { + final SftpFileSystemConfigBuilder builder = SftpFileSystemConfigBuilder.getInstance(); + + final FileSystemOptions expected = new FileSystemOptions(); + final IdentityInfo info1 = new IdentityInfo(privKey, pubKey, passphrase); + builder.setIdentityProvider(expected, info1); + + final FileSystemOptions actual = new FileSystemOptions(); + final IdentityInfo info2 = new IdentityInfo(privKey, pubKey, passphrase); + builder.setIdentityProvider(actual, info2); + + assertEquals(0, expected.compareTo(actual)); + assertEquals(expected.hashCode(), actual.hashCode()); + } + + private static void assertSftpOptionsNotEquals(final File privKey1, final File pubKey1, final byte[] passphrase1, + final File privKey2, final File pubKey2, final byte[] passphrase2) { + final SftpFileSystemConfigBuilder builder = SftpFileSystemConfigBuilder.getInstance(); + + final FileSystemOptions expected = new FileSystemOptions(); + final IdentityInfo info1 = new IdentityInfo(privKey1, pubKey1, passphrase1); + builder.setIdentityProvider(expected, info1); + + final FileSystemOptions actual = new FileSystemOptions(); + final IdentityInfo info2 = new IdentityInfo(privKey2, pubKey2, passphrase2); + builder.setIdentityProvider(actual, info2); + + assertNotEquals(0, expected.compareTo(actual)); + assertNotEquals(expected.hashCode(), actual.hashCode()); + } + + @Test + public void testClone() { + final FileSystemOptions fileSystemOptions = new FileSystemOptions(); + assertEquals(fileSystemOptions.getClass(), fileSystemOptions.clone().getClass()); + assertEquals(0, ((FileSystemOptions) fileSystemOptions.clone()).size()); + fileSystemOptions.setOption(FileSystem.class, "key1", "value1"); + assertEquals(1, ((FileSystemOptions) fileSystemOptions.clone()).size()); + final FileSystemOptions clone = (FileSystemOptions) fileSystemOptions.clone(); + assertEquals("value1", clone.getOption(FileSystem.class, "key1")); + fileSystemOptions.setOption(FileSystem.class, "key2", "value2"); + assertNull(clone.getOption(FileSystem.class, "key2")); + } + + @Test + public void testEqualsHashCodeAndCompareTo() { + final JUnitConfigBuilder builder = JUnitConfigBuilder.getInstance(); + final FileSystemOptions expected = new FileSystemOptions(); + builder.setId(expected, "Test"); + + final FileSystemOptions actual = new FileSystemOptions(); + builder.setId(actual, "Test"); + + assertEquals(expected, actual); + assertEquals(0, actual.compareTo(expected)); + assertEquals(expected.hashCode(), actual.hashCode()); + + builder.setNames(expected, new String[] {"A", "B", "C"}); + + assertNotEquals(expected, actual); + assertEquals(-1, actual.compareTo(expected)); + assertNotEquals(expected.hashCode(), actual.hashCode()); + + builder.setNames(actual, new String[] {"A", "B", "C"}); + + assertEquals(expected, actual); + assertEquals(0, actual.compareTo(expected)); + assertEquals(expected.hashCode(), actual.hashCode()); + } + + @Test + public void testEqualsHashCodeAndCompareToWithSftpIdentityProviderMatch() { + for (int mask = 0; mask < 8; mask++) { + assertSftpOptionsEquals( + (mask & 1) == 1 ? new File("/tmp/test.priv") : null, + (mask & 2) == 2 ? new File("/tmp/test.pub") : null, + (mask & 4) == 4 ? new byte[] {1, 2, 3} : null + ); + } + } + + @Test + public void testEqualsHashCodeAndCompareToWithSftpIdentityProviderMismatch() { + final String pubKey1 = "/tmp/test.pub"; + final String pubKey2 = "/tmp/test1.pub"; + + final String privKey1 = "/tmp/test.priv"; + final String privKey2 = "/tmp/test1.priv"; + + assertSftpOptionsNotEquals( + new File(privKey1), new File(pubKey1), new byte[] {1, 2, 3}, + new File(privKey2), new File(pubKey1), new byte[] {1, 2, 3} + ); + + assertSftpOptionsNotEquals( + new File(privKey1), new File(pubKey1), new byte[] {1, 2, 3}, + new File(privKey1), new File(pubKey2), new byte[] {1, 2, 3} + ); + + assertSftpOptionsNotEquals( + new File(privKey1), new File(pubKey1), new byte[] {1, 2, 3}, + new File(privKey1), new File(pubKey1), new byte[] {1, 2, 4} + ); + } +} diff --git a/commons-vfs2/src/test/java/org/apache/commons/vfs2/provider/test/FileObjectSortTest.java b/commons-vfs2/src/test/java/org/apache/commons/vfs2/provider/test/FileObjectSortTest.java index e69b1a4fd7..b0b05e7203 100644 --- a/commons-vfs2/src/test/java/org/apache/commons/vfs2/provider/test/FileObjectSortTest.java +++ b/commons-vfs2/src/test/java/org/apache/commons/vfs2/provider/test/FileObjectSortTest.java @@ -1,130 +1,130 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.vfs2.provider.test; - -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotEquals; - -import java.util.Arrays; -import java.util.List; - -import org.apache.commons.vfs2.FileObject; -import org.apache.commons.vfs2.FileSystem; -import org.apache.commons.vfs2.FileSystemException; -import org.apache.commons.vfs2.VFS; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -/** - * Tests FileObject sorting. - */ -public class FileObjectSortTest { - - /** - * The size of arrays to sort. - */ - private static final int SIZE = 100; - - /** Consider @Immutable. */ - private static FileSystem vfsFileSystem; - - /** Consider @Immutable */ - private static FileObject[] sortedArray; - - /** Consider @Immutable */ - private static FileObject[] unSortedArray; - - private static FileObject resolveFile(final FileSystem fs, final int i) throws FileSystemException { - return fs.resolveFile(String.format("%010d", i)); - } - - @BeforeAll - public static void setUpClass() throws FileSystemException { - vfsFileSystem = VFS.getManager().createVirtualFileSystem("vfs://").getFileSystem(); - sortedArray = new FileObject[SIZE]; - for (int i = 0; i < SIZE; i++) { - sortedArray[i] = FileObjectSortTest.resolveFile(vfsFileSystem, i); - } - unSortedArray = new FileObject[SIZE]; - for (int i = 0; i < SIZE; i++) { - unSortedArray[i] = FileObjectSortTest.resolveFile(vfsFileSystem, SIZE - i - 1); - } - } - - /** - * Tests that sorting ignores case. - * - * @throws FileSystemException - */ - @Test - public void testSortArrayIgnoreCase() throws FileSystemException { - final FileObject file1 = vfsFileSystem.resolveFile("A1"); - final FileObject file2 = vfsFileSystem.resolveFile("a2"); - final FileObject file3 = vfsFileSystem.resolveFile("A3"); - final FileObject[] actualArray = { file3, file1, file2, file1, file2 }; - final FileObject[] expectedArray = { file1, file1, file2, file2, file3 }; - Arrays.sort(actualArray); - assertArrayEquals(expectedArray, actualArray); - } - - /** - * Tests sorting an array. - */ - @Test - public void testSortArrayMoveAll() { - final FileObject[] actualArray = unSortedArray.clone(); - assertFalse(Arrays.equals(unSortedArray, sortedArray)); - Arrays.sort(actualArray); - assertArrayEquals(sortedArray, actualArray); - } - - /** - * Tests that sorting an array already in oder does not mess it up. - */ - @Test - public void testSortArrayMoveNone() { - final FileObject[] actualArray = sortedArray.clone(); - Arrays.sort(actualArray); - assertArrayEquals(sortedArray, actualArray); - } - - /** - * Tests sorting a list. - */ - @Test - public void testSortListMoveAll() { - final List actualList = Arrays.asList(unSortedArray); - final List expectedSortedList = Arrays.asList(sortedArray); - assertNotEquals(actualList, expectedSortedList); - actualList.sort(null); - assertEquals(actualList, expectedSortedList); - } - - /** - * Tests that sorting a list already in oder does not mess it up. - */ - @Test - public void testSortListMoveNone() { - final List actualList = Arrays.asList(sortedArray); - final List expectedSortedList = Arrays.asList(sortedArray); - actualList.sort(null); - assertEquals(actualList, expectedSortedList); - } - -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.vfs2.provider.test; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; + +import java.util.Arrays; +import java.util.List; + +import org.apache.commons.vfs2.FileObject; +import org.apache.commons.vfs2.FileSystem; +import org.apache.commons.vfs2.FileSystemException; +import org.apache.commons.vfs2.VFS; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +/** + * Tests FileObject sorting. + */ +public class FileObjectSortTest { + + /** + * The size of arrays to sort. + */ + private static final int SIZE = 100; + + /** Consider @Immutable. */ + private static FileSystem vfsFileSystem; + + /** Consider @Immutable */ + private static FileObject[] sortedArray; + + /** Consider @Immutable */ + private static FileObject[] unSortedArray; + + private static FileObject resolveFile(final FileSystem fs, final int i) throws FileSystemException { + return fs.resolveFile(String.format("%010d", i)); + } + + @BeforeAll + public static void setUpClass() throws FileSystemException { + vfsFileSystem = VFS.getManager().createVirtualFileSystem("vfs://").getFileSystem(); + sortedArray = new FileObject[SIZE]; + for (int i = 0; i < SIZE; i++) { + sortedArray[i] = FileObjectSortTest.resolveFile(vfsFileSystem, i); + } + unSortedArray = new FileObject[SIZE]; + for (int i = 0; i < SIZE; i++) { + unSortedArray[i] = FileObjectSortTest.resolveFile(vfsFileSystem, SIZE - i - 1); + } + } + + /** + * Tests that sorting ignores case. + * + * @throws FileSystemException + */ + @Test + public void testSortArrayIgnoreCase() throws FileSystemException { + final FileObject file1 = vfsFileSystem.resolveFile("A1"); + final FileObject file2 = vfsFileSystem.resolveFile("a2"); + final FileObject file3 = vfsFileSystem.resolveFile("A3"); + final FileObject[] actualArray = { file3, file1, file2, file1, file2 }; + final FileObject[] expectedArray = { file1, file1, file2, file2, file3 }; + Arrays.sort(actualArray); + assertArrayEquals(expectedArray, actualArray); + } + + /** + * Tests sorting an array. + */ + @Test + public void testSortArrayMoveAll() { + final FileObject[] actualArray = unSortedArray.clone(); + assertFalse(Arrays.equals(unSortedArray, sortedArray)); + Arrays.sort(actualArray); + assertArrayEquals(sortedArray, actualArray); + } + + /** + * Tests that sorting an array already in oder does not mess it up. + */ + @Test + public void testSortArrayMoveNone() { + final FileObject[] actualArray = sortedArray.clone(); + Arrays.sort(actualArray); + assertArrayEquals(sortedArray, actualArray); + } + + /** + * Tests sorting a list. + */ + @Test + public void testSortListMoveAll() { + final List actualList = Arrays.asList(unSortedArray); + final List expectedSortedList = Arrays.asList(sortedArray); + assertNotEquals(actualList, expectedSortedList); + actualList.sort(null); + assertEquals(actualList, expectedSortedList); + } + + /** + * Tests that sorting a list already in oder does not mess it up. + */ + @Test + public void testSortListMoveNone() { + final List actualList = Arrays.asList(sortedArray); + final List expectedSortedList = Arrays.asList(sortedArray); + actualList.sort(null); + assertEquals(actualList, expectedSortedList); + } + +} diff --git a/commons-vfs2/src/test/resources/log4j.properties b/commons-vfs2/src/test/resources/log4j.properties index 3a98c2eb3f..ca5bb83244 100644 --- a/commons-vfs2/src/test/resources/log4j.properties +++ b/commons-vfs2/src/test/resources/log4j.properties @@ -1,36 +1,36 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -# @version $Id: log4j.properties 27216 2011-09-14 02:34:00Z ggregory $ - -log4j.rootLogger=ERROR, Console -#log4j.rootLogger=WARN, Console -#log4j.rootLogger=INFO, Console -#log4j.rootLogger=DEBUG, Console - -############################################################################### -# The console log -# -# Documentation: https://logging.apache.org/log4j/2.x/log4j-core/apidocs/org/apache/logging/log4j/core/appender/ConsoleAppender.html -# -# To enable this appender, add its name to the log4j.rootLogger list - -log4j.appender.Console=org.apache.log4j.ConsoleAppender -log4j.appender.Console.ImmediateFlush=true -log4j.appender.Console.Target=System.out -log4j.appender.Console.layout=org.apache.log4j.PatternLayout -log4j.appender.Console.layout.ConversionPattern=%d{ISO8601} [%t] %-5p: %m%n +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# @version $Id: log4j.properties 27216 2011-09-14 02:34:00Z ggregory $ + +log4j.rootLogger=ERROR, Console +#log4j.rootLogger=WARN, Console +#log4j.rootLogger=INFO, Console +#log4j.rootLogger=DEBUG, Console + +############################################################################### +# The console log +# +# Documentation: https://logging.apache.org/log4j/2.x/log4j-core/apidocs/org/apache/logging/log4j/core/appender/ConsoleAppender.html +# +# To enable this appender, add its name to the log4j.rootLogger list + +log4j.appender.Console=org.apache.log4j.ConsoleAppender +log4j.appender.Console.ImmediateFlush=true +log4j.appender.Console.Target=System.out +log4j.appender.Console.layout=org.apache.log4j.PatternLayout +log4j.appender.Console.layout.ConversionPattern=%d{ISO8601} [%t] %-5p: %m%n diff --git a/commons-vfs2/src/test/resources/org.apache.ftpserver/users.properties b/commons-vfs2/src/test/resources/org.apache.ftpserver/users.properties index fadf36c410..59fe696087 100644 --- a/commons-vfs2/src/test/resources/org.apache.ftpserver/users.properties +++ b/commons-vfs2/src/test/resources/org.apache.ftpserver/users.properties @@ -1,43 +1,43 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -# Password is "admin" -ftpserver.user.admin.userpassword=21232F297A57A5A743894A0E4A801FC3 -ftpserver.user.admin.homedirectory=target/test-classes/test-data -ftpserver.user.admin.enableflag=true -ftpserver.user.admin.writepermission=true -ftpserver.user.admin.maxloginnumber=0 -ftpserver.user.admin.maxloginperip=0 -ftpserver.user.admin.idletime=0 -ftpserver.user.admin.uploadrate=0 -ftpserver.user.admin.downloadrate=0 - -ftpserver.user.anonymous.userpassword= -ftpserver.user.anonymous.homedirectory=target/test-classes/test-data -ftpserver.user.anonymous.enableflag=true -ftpserver.user.anonymous.writepermission=false -ftpserver.user.anonymous.maxloginnumber=20 -ftpserver.user.anonymous.maxloginperip=2 -ftpserver.user.anonymous.idletime=300 -ftpserver.user.anonymous.uploadrate=4800 -ftpserver.user.anonymous.downloadrate=4800 - -# password is "test" -ftpserver.user.test.userpassword=098f6bcd4621d373cade4e832627b4f6 -ftpserver.user.test.homedirectory=target/test-classes/test-data -ftpserver.user.test.enableflag=true -ftpserver.user.test.writepermission=true +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# Password is "admin" +ftpserver.user.admin.userpassword=21232F297A57A5A743894A0E4A801FC3 +ftpserver.user.admin.homedirectory=target/test-classes/test-data +ftpserver.user.admin.enableflag=true +ftpserver.user.admin.writepermission=true +ftpserver.user.admin.maxloginnumber=0 +ftpserver.user.admin.maxloginperip=0 +ftpserver.user.admin.idletime=0 +ftpserver.user.admin.uploadrate=0 +ftpserver.user.admin.downloadrate=0 + +ftpserver.user.anonymous.userpassword= +ftpserver.user.anonymous.homedirectory=target/test-classes/test-data +ftpserver.user.anonymous.enableflag=true +ftpserver.user.anonymous.writepermission=false +ftpserver.user.anonymous.maxloginnumber=20 +ftpserver.user.anonymous.maxloginperip=2 +ftpserver.user.anonymous.idletime=300 +ftpserver.user.anonymous.uploadrate=4800 +ftpserver.user.anonymous.downloadrate=4800 + +# password is "test" +ftpserver.user.test.userpassword=098f6bcd4621d373cade4e832627b4f6 +ftpserver.user.test.homedirectory=target/test-classes/test-data +ftpserver.user.test.enableflag=true +ftpserver.user.test.writepermission=true diff --git a/commons-vfs2/src/test/resources/test-data/read-xml-tests/address.xsd b/commons-vfs2/src/test/resources/test-data/read-xml-tests/address.xsd index 065648abcd..81309a9670 100644 --- a/commons-vfs2/src/test/resources/test-data/read-xml-tests/address.xsd +++ b/commons-vfs2/src/test/resources/test-data/read-xml-tests/address.xsd @@ -1,45 +1,45 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + diff --git a/commons-vfs2/src/test/resources/test-data/read-xml-tests/file1.xml b/commons-vfs2/src/test/resources/test-data/read-xml-tests/file1.xml index 42e9846ec7..c7ef3698db 100644 --- a/commons-vfs2/src/test/resources/test-data/read-xml-tests/file1.xml +++ b/commons-vfs2/src/test/resources/test-data/read-xml-tests/file1.xml @@ -1,18 +1,18 @@ - - -foo1 + + +foo1 diff --git a/commons-vfs2/src/test/resources/test-data/read-xml-tests/file2.xml b/commons-vfs2/src/test/resources/test-data/read-xml-tests/file2.xml index 2e3ff38237..78cb379bfc 100644 --- a/commons-vfs2/src/test/resources/test-data/read-xml-tests/file2.xml +++ b/commons-vfs2/src/test/resources/test-data/read-xml-tests/file2.xml @@ -1,18 +1,18 @@ - - -foo2 + + +foo2 diff --git a/commons-vfs2/src/test/resources/test-data/read-xml-tests/file3-bigger.xml b/commons-vfs2/src/test/resources/test-data/read-xml-tests/file3-bigger.xml index 780dc4860c..53e655cae6 100644 --- a/commons-vfs2/src/test/resources/test-data/read-xml-tests/file3-bigger.xml +++ b/commons-vfs2/src/test/resources/test-data/read-xml-tests/file3-bigger.xml @@ -1,1354 +1,1354 @@ - - - - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 - + + + + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 foo1 + diff --git a/commons-vfs2/src/test/resources/test-data/read-xml-tests/name-invalid.xml b/commons-vfs2/src/test/resources/test-data/read-xml-tests/name-invalid.xml index 522c4f6f3f..8c3f9f327c 100644 --- a/commons-vfs2/src/test/resources/test-data/read-xml-tests/name-invalid.xml +++ b/commons-vfs2/src/test/resources/test-data/read-xml-tests/name-invalid.xml @@ -1,25 +1,25 @@ - - - - John - Q. - Public - + + + + John + Q. + Public + diff --git a/commons-vfs2/src/test/resources/test-data/read-xml-tests/name-not-well-formed.xml b/commons-vfs2/src/test/resources/test-data/read-xml-tests/name-not-well-formed.xml index 305ac6eba8..31dbdd1bb4 100644 --- a/commons-vfs2/src/test/resources/test-data/read-xml-tests/name-not-well-formed.xml +++ b/commons-vfs2/src/test/resources/test-data/read-xml-tests/name-not-well-formed.xml @@ -1,24 +1,24 @@ - - - - John - Q. - Public + + + + John + Q. + Public diff --git a/commons-vfs2/src/test/resources/test-data/read-xml-tests/name-with-xsd-ref.xml b/commons-vfs2/src/test/resources/test-data/read-xml-tests/name-with-xsd-ref.xml index cad2771282..e2f171c010 100644 --- a/commons-vfs2/src/test/resources/test-data/read-xml-tests/name-with-xsd-ref.xml +++ b/commons-vfs2/src/test/resources/test-data/read-xml-tests/name-with-xsd-ref.xml @@ -1,25 +1,25 @@ - - - - John - Q. - Public - + + + + John + Q. + Public + diff --git a/commons-vfs2/src/test/resources/test-data/read-xml-tests/name.xml b/commons-vfs2/src/test/resources/test-data/read-xml-tests/name.xml index 4c5c870722..fb60df3b55 100644 --- a/commons-vfs2/src/test/resources/test-data/read-xml-tests/name.xml +++ b/commons-vfs2/src/test/resources/test-data/read-xml-tests/name.xml @@ -1,22 +1,22 @@ - - - - John - Q. - Public - + + + + John + Q. + Public + diff --git a/commons-vfs2/src/test/resources/test-data/read-xml-tests/name.xsd b/commons-vfs2/src/test/resources/test-data/read-xml-tests/name.xsd index 9b0a6a7193..98611639ff 100644 --- a/commons-vfs2/src/test/resources/test-data/read-xml-tests/name.xsd +++ b/commons-vfs2/src/test/resources/test-data/read-xml-tests/name.xsd @@ -1,42 +1,42 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/commons-vfs2/src/test/resources/test-data/read-xml-tests/person.xml b/commons-vfs2/src/test/resources/test-data/read-xml-tests/person.xml index 28e023f633..1b375b84c0 100644 --- a/commons-vfs2/src/test/resources/test-data/read-xml-tests/person.xml +++ b/commons-vfs2/src/test/resources/test-data/read-xml-tests/person.xml @@ -1,38 +1,38 @@ - - - - - - John - Q. - Public - - - - 123 Main St. - Ridgway - CO - 81432 - - - + + + + + + John + Q. + Public + + + + 123 Main St. + Ridgway + CO + 81432 + + + diff --git a/commons-vfs2/src/test/resources/test-data/read-xml-tests/person.xsd b/commons-vfs2/src/test/resources/test-data/read-xml-tests/person.xsd index 4bc82a9408..8c43bd84fe 100644 --- a/commons-vfs2/src/test/resources/test-data/read-xml-tests/person.xsd +++ b/commons-vfs2/src/test/resources/test-data/read-xml-tests/person.xsd @@ -1,48 +1,48 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + diff --git a/src/changes/release-notes.vm b/src/changes/release-notes.vm index 301fe5678a..7552e14e5b 100644 --- a/src/changes/release-notes.vm +++ b/src/changes/release-notes.vm @@ -1,134 +1,134 @@ -## Licensed to the Apache Software Foundation (ASF) under one -## or more contributor license agreements. See the NOTICE file -## distributed with this work for additional information -## regarding copyright ownership. The ASF licenses this file -## to you under the Apache License, Version 2.0 (the -## "License"); you may not use this file except in compliance -## with the License. You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, -## software distributed under the License is distributed on an -## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -## KIND, either express or implied. See the License for the -## specific language governing permissions and limitations -## under the License. -## -${project.name} ${version} -RELEASE NOTES - -The ${developmentTeam} is pleased to announce the release of ${project.name} ${version}. - -$introduction.replaceAll("(?